Codificación Base64 en SQL Server 2005 T-SQL

124

Me gustaría escribir una consulta T-SQL donde codifico una cadena como una cadena Base64. Sorprendentemente, no puedo encontrar ninguna función T-SQL nativa para hacer la codificación Base64. ¿Existe una función nativa? Si no, ¿cuál es la mejor manera de hacer la codificación Base64 en T-SQL?

Jacob
fuente
1
Me preguntaría por qué los datos deben almacenarse como una cadena base64. Hay una buena razón para usar base64 sobre http, a saber, que garantiza la interoperabilidad entre sistemas que no admiten nada más que el conjunto de caracteres ASCII (y que tratan todos los datos como texto). Puede convertir fácilmente una matriz de bytes a base-64 y viceversa, entonces, ¿por qué no almacenar los datos de manera eficiente? Incluso he visto a la gente almacena en base 64 cadenas en columnas nvarchar, que tarda 275% del espacio de varbinary, con el consiguiente derroche de disco, memoria RAM, red, etc.
El Dag
9
Se trata de generar una cadena base64, no almacenar una.
Jacob

Respuestas:

187

Sé que esto ya ha sido respondido, pero acabo de pasar más tiempo del que me gustaría admitir creando declaraciones SQL de una sola línea para lograr esto, así que las compartiré aquí en caso de que alguien más necesite hacer lo mismo:

-- 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
;

Tuve que usar una tabla generada por subconsulta en la primera consulta (codificación) porque no pude encontrar ninguna forma de convertir el valor original ("TestData") a su representación de cadena hexadecimal ("5465737444617461") para incluir como argumento para xs: hexBinary () en la instrucción XQuery.

¡Espero que esto ayude a alguien!

mercurial
fuente
77
Al codificar, xs:base64Binary(sql:column("bin"))(sin la xs:hexBinaryllamada) también funciona. ¡Gran ayuda!
anfetamáquina
3
Para admitir la codificación del texto unicode, debe agregar 'N' delante de TestData : 'SELECT CAST ( N ' TestData 'AS VARBINARY (MAX)) AS bin'
Kjetil Klaussen
No funcionó para texto Unicode ... SELECT CAST (N '' AS XML) .value ('xs: base64Binary (xs: hexBinary (sql: column ("bin")))', 'VARCHAR (MAX)') Base64Encoding FROM (SELECT CAST (N 'मन्त्रीले उल्ट्याए सात छन्।' AS VARBINARY (MAX)) AS bin) AS bin_sql_server_temp;
hsuk
3
@hsuk varchar no es compatible con Unicode. Funciona bien si usa nvarchar (max) en su lugar, por ejemplo:SELECT CAST( CAST(N'' AS XML).value( 'xs:base64Binary("LgkoCU0JJAlNCTAJQAkyCUcJIAAJCTIJTQkfCU0JLwk+CQ8JIAA4CT4JJAkgABsJKAlNCWQJ")' , 'VARBINARY(MAX)' ) AS NVARCHAR(MAX) ) UnicodeEncoding ;
AlwaysLearning
77
¿Porque a veces la gente necesita lograr ciertas cosas en el software por razones que no siempre puede predecir ...?
mercurial
87

La forma más simple y corta que pude encontrar para SQL Server 2012 y superior es BINARY BASE64:

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

Para Base64 en cadena

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

(o nvarchar(max)para cadenas Unicode)

Slai
fuente
1
Esto es mucho más simple que las otras respuestas, y funciona igual de bien
sXe
2
¿Cuál es el propósito de BINARY BASE64 en la primera línea? ¿Es necesario? Lo intenté sin y parece dar el mismo resultado.
mattpm
1
El primer fragmento me dio un resultado diferente de lo que esperaba; Cambié "varbinary" a "varbinary (max)" y los caracteres que faltaban
encajaron
3
Esta debería ser la respuesta porque la respuesta real requiere literales de cadena y no puede aceptar variables como esta respuesta puede.
Matthew
2
Para base64 en cadena, noto una ganancia de rendimiento significativa con .value ('data [1]', 'varbinary (max)') vice .value ('.', 'Varbinary (max)').
Geary M. McIver
25

Aquí hay una modificación a la respuesta de mercurial que también usa la subconsulta en la decodificación, permitiendo el uso de variables en ambas instancias.

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
fuente
22

Aquí está el código para las funciones que harán el trabajo.

-- 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

Ejemplo de uso:

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

ingrese la descripción de la imagen aquí

Oleg
fuente
En general útil. Esto no manejó ningún personaje como persa y ruso, o emoji. por ejemplo, سلام جیران o В России Base64 кодирует вас o ❤️💥🤪🦌🎅⛄🎄🤐🙈🙉🙊💩
Hunter-Orionnoir
Tienes razón. Se maneja después de reemplazar varchar a nvarchar
Oleg
8

Me encantó la respuesta de @ Slai. Solo tuve que hacer modificaciones muy pequeñas en las frases que buscaba. Pensé en compartir lo que terminé en caso de que ayude a alguien a tropezar con esta página como lo hice yo:

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
fuente
Para mí, necesitaba cambiar la segunda línea VARBINARYa VARBINARY(56), y luego funcionó.
Lee Grissom
La solución más corta, compatible con 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]

Esto es útil para codificar y decodificar.

Por Bharat J

Bharat J
fuente
0

Hice un script para convertir un hash existente codificado en base64 a decimal, puede ser útil:

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

Puedes usar solo:

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

luego, después de la codificación, recibirá el texto 'MjE4Nqk5'

jasmintmp
fuente