Codificação Base64 no SQL Server 2005 T-SQL

124

Eu gostaria de escrever uma consulta T-SQL em que codifico uma string como uma string Base64. Surpreendentemente, não consigo encontrar nenhuma função T-SQL nativa para codificação Base64. Existe uma função nativa? Caso contrário, qual é a melhor maneira de fazer a codificação Base64 no T-SQL?

Jacob
fonte
1
Eu questionaria por que os dados devem ser armazenados como uma string base64. Há um bom motivo para usar o base64 sobre http, a saber, que ele garante a interoperabilidade entre sistemas que suportam nada além do conjunto de caracteres ASCII (e que tratam todos os dados como texto). Você pode converter facilmente uma matriz de bytes em base-64 e vice-versa. Por que não armazenar os dados com eficiência? Eu mesmo vi pessoas armazenam base64-cordas em colunas nvarchar, o que leva 275% do espaço de varbinary, levando ao desperdício de disco, memória RAM, rede, etc.
O Dag
9
Trata-se de gerar uma string base64, não de armazenar uma.
Jacob

Respostas:

187

Sei que isso já foi respondido, mas dediquei mais tempo do que gostaria de admitir a criar instruções SQL de linha única para fazer isso, então as compartilharei aqui caso outras pessoas precisem fazer o mesmo:

-- Encode the string "TestData" in Base64 to get "VGVzdERhdGE="
SELECT
    CAST(N'' AS XML).value(
          'xs:base64Binary(xs:hexBinary(sql:column("bin")))'
        , 'VARCHAR(MAX)'
    )   Base64Encoding
FROM (
    SELECT CAST('TestData' AS VARBINARY(MAX)) AS bin
) AS bin_sql_server_temp;

-- Decode the Base64-encoded string "VGVzdERhdGE=" to get back "TestData"
SELECT 
    CAST(
        CAST(N'' AS XML).value(
            'xs:base64Binary("VGVzdERhdGE=")'
          , 'VARBINARY(MAX)'
        ) 
        AS VARCHAR(MAX)
    )   ASCIIEncoding
;

Eu tive que usar uma tabela gerada por subconsulta na primeira consulta (codificação) porque não consegui encontrar nenhuma maneira de converter o valor original ("TestData") em sua representação de cadeia hexadecimal ("5465737444617461") para incluir como argumento para xs: hexBinary () na instrução XQuery.

Espero que isso ajude alguém!

mercurial
fonte
7
Ao codificar, xs:base64Binary(sql:column("bin"))(sem a xs:hexBinarychamada) também funciona. Ótima ajuda!
Amphetamachine
3
Para oferecer suporte à codificação de texto unicode, você deve adicionar 'N' na frente do TestData : 'SELECT CAST ( N ' TestData 'COMO VARBINARY (MAX)) AS bin'
Kjetil Klaussen
Não funcionou para texto unicode ... SELECT CAST (N '' AS XML) .value ('xs: base64Binary (xs: hexBinary (sql: column ("bin"))))', 'VARCHAR (MAX)') Base64Encoding FROM (SELECIONAR CAST (N 'मन्त्रीले उल्ट्याए सात छन्।' AS VARBINARY (MAX)) AS bin) AS bin_sql_server_temp;
Hsuk
3
O @hsuk varchar não é compatível com Unicode. Funciona bem se você usar o nvarchar (max), por exemplo:SELECT CAST( CAST(N'' AS XML).value( 'xs:base64Binary("LgkoCU0JJAlNCTAJQAkyCUcJIAAJCTIJTQkfCU0JLwk+CQ8JIAA4CT4JJAkgABsJKAlNCWQJ")' , 'VARBINARY(MAX)' ) AS NVARCHAR(MAX) ) UnicodeEncoding ;
AlwaysLearning
7
Porque às vezes as pessoas precisam realizar certas coisas no software por razões que você nem sempre pode prever ...?
precisa
87

A maneira mais simples e curta que eu poderia encontrar para o SQL Server 2012 e acima é BINARY BASE64:

SELECT CAST('string' as varbinary(max)) FOR XML PATH(''), BINARY BASE64

Para Base64 para string

SELECT CAST( CAST( 'c3RyaW5n' as XML ).value('.','varbinary(max)') AS varchar(max) )

(ou nvarchar(max)para cadeias Unicode)

Slai
fonte
1
Isto é muito mais simples do que as outras respostas, e funciona tão bem
sXe
2
qual é o objetivo de BINARY BASE64 na primeira linha? É necessário? Eu tentei sem e parece dar o mesmo resultado.
mattpm
1
O primeiro trecho me deu um resultado diferente do que eu esperava; Eu mudei "varbinary" para "varbinary (max)" e os caracteres em falta se encaixou
Hraefn
3
Essa deve ser a resposta, porque a resposta real requer literais de string e não pode aceitar variáveis ​​como essa resposta.
Matthew
2
Para base64 para string, estou percebendo um ganho de desempenho significativo com .value ('data [1]', 'varbinary (max)') vice .value ('.', 'Varbinary (max)').
Geary M. McIver
25

Aqui está uma modificação na resposta do mercurial que também usa a subconsulta na decodificação, permitindo o uso de variáveis ​​nos dois casos.

DECLARE
    @EncodeIn VARCHAR(100) = 'Test String In',
    @EncodeOut VARCHAR(500),
    @DecodeOut VARCHAR(200)    

SELECT @EncodeOut = 
    CAST(N'' AS XML).value(
          'xs:base64Binary(xs:hexBinary(sql:column("bin")))'
        , 'VARCHAR(MAX)'
    )
FROM (
    SELECT CAST(@EncodeIn AS VARBINARY(MAX)) AS bin
) AS bin_sql_server_temp;

PRINT @EncodeOut

SELECT @DecodeOut = 
CAST(
    CAST(N'' AS XML).value(
        'xs:base64Binary(sql:column("bin"))'
      , 'VARBINARY(MAX)'
    ) 
    AS VARCHAR(MAX)
) 
FROM (
    SELECT CAST(@EncodeOut AS VARCHAR(MAX)) AS bin
) AS bin_sql_server_temp;

PRINT @DecodeOut
Joey Gennari
fonte
22

Aqui está o código para as funções que farão o trabalho

-- To Base64 string
CREATE FUNCTION [dbo].[fn_str_TO_BASE64]
(
    @STRING NVARCHAR(MAX)
)
RETURNS NVARCHAR(MAX)
AS
BEGIN
    RETURN (
        SELECT
            CAST(N'' AS XML).value(
                  'xs:base64Binary(xs:hexBinary(sql:column("bin")))'
                , 'NVARCHAR(MAX)'
            )   Base64Encoding
        FROM (
            SELECT CAST(@STRING AS VARBINARY(MAX)) AS bin
        ) AS bin_sql_server_temp
    )
END
GO

-- From Base64 string
CREATE FUNCTION [dbo].[fn_str_FROM_BASE64]
(
    @BASE64_STRING NVARCHAR(MAX)
)
RETURNS NVARCHAR(MAX)
AS
BEGIN
    RETURN (
        SELECT 
            CAST(
                CAST(N'' AS XML).value('xs:base64Binary(sql:variable("@BASE64_STRING"))', 'VARBINARY(MAX)') 
            AS NVARCHAR(MAX)
            )   UTF8Encoding
    )
END

Exemplo de uso:

DECLARE @CHAR NVARCHAR(256) = N'e.g., سلام جیران or В России'
SELECT [dbo].[fn_str_FROM_BASE64]([dbo].[fn_str_TO_BASE64](@CHAR)) as converted

insira a descrição da imagem aqui

Oleg
fonte
Geralmente útil. Isso não lidava com caracteres como persa e russo ou emoji. por exemplo, سلام جیران ou В России Base64 кодирует вас ou ❤️💥🤪🦌🎅⛄🎄🤐🙈🙉🙊💩
Hunter-Orionnoir
Você está certo. Ele lida com a substituição de varchar para nvarchar
Oleg
8

Adorei a resposta de @ Slai. Eu só tive que fazer modificações muito pequenas nas linhas que eu estava procurando. Pensei em compartilhar o que acabei, caso isso ajude mais alguém a tropeçar nessa página como eu fiz:

DECLARE @Source VARCHAR(50) = '12345'
DECLARE @Encoded VARCHAR(500) = CONVERT(VARCHAR(500), (SELECT CONVERT(VARBINARY, @Source) FOR XML PATH(''), BINARY BASE64))
DECLARE @Decoded VARCHAR(500) = CONVERT(VARCHAR(500), CONVERT(XML, @Encoded).value('.','varbinary(max)'))
SELECT @Source AS [Source], @Encoded AS [Encoded], @Decoded AS [Decoded]
Jason W
fonte
Para mim, eu precisei mudar a segunda linha VARBINARYpara VARBINARY(56)e funcionou.
Lee Grissom
Solução mais curta, compatível com o SQL Server 2005+.
YB
1
DECLARE @source varbinary(max),  
@encoded_base64 varchar(max),  
@decoded varbinary(max) 
SET @source = CONVERT(varbinary(max), 'welcome') 
-- Convert from varbinary to base64 string 
SET @encoded_base64 = CAST(N'' AS xml).value('xs:base64Binary(sql:variable       
("@source"))', 'varchar(max)') 
  -- Convert back from base64 to varbinary 
   SET @decoded = CAST(N'' AS xml).value('xs:base64Binary(sql:variable             
  ("@encoded_base64"))', 'varbinary(max)') 

 SELECT
  CONVERT(varchar(max), @source) AS [Source varchar], 
   @source AS [Source varbinary], 
     @encoded_base64 AS [Encoded base64], 
     @decoded AS [Decoded varbinary], 
     CONVERT(varchar(max), @decoded) AS [Decoded varchar]

Isso é útil para codificar e decodificar.

Por Bharat J

Bharat J
fonte
0

Eu fiz um script para converter um hash existente codificado em base64 em decimal, pode ser útil:

SELECT LOWER(SUBSTRING(CONVERT(NVARCHAR(42), CAST( [COLUMN_NAME] as XML ).value('.','varbinary(max)'), 1), 3, 40)) from TABLE
Phate01
fonte
-1

Você pode usar apenas:

Declare @pass2 binary(32)
Set @pass2 =0x4D006A00450034004E0071006B00350000000000000000000000000000000000
SELECT CONVERT(NVARCHAR(16), @pass2)

depois da codificação, você receberá o texto 'MjE4Nqk5'

jasmintmp
fonte