Codifica Base64 in SQL Server 2005 T-SQL


124

Vorrei scrivere una query T-SQL in cui codifico una stringa come stringa Base64. Sorprendentemente, non riesco a trovare alcuna funzione T-SQL nativa per la codifica Base64. Esiste una funzione nativa? In caso contrario, qual è il modo migliore per eseguire la codifica Base64 in T-SQL?


1
Mi chiedo perché i dati dovrebbero essere archiviati come una stringa base64. C'è una buona ragione per usare base64 su http, vale a dire che garantisce l'interoperabilità tra sistemi che supportano nient'altro che il set di caratteri ASCII (e che trattano tutti i dati come testo). Puoi convertire facilmente un array di byte in base 64 e viceversa, quindi perché non archiviare i dati in modo efficiente? Ho persino visto persone memorizzare stringhe base64 nelle colonne nvarchar, che occupa il 275% dello spazio di varbinary, portando allo spreco di disco, ram, rete, ecc.
Il giorno

9
Si tratta di generare una stringa base64, non di memorizzarne una.
Jacob il

Risposte:


187

So che è già stata data una risposta, ma ho appena trascorso più tempo di quanto mi interessa ammettere di elaborare istruzioni SQL su una sola riga per ottenere questo risultato, quindi le condividerò qui nel caso in cui qualcun altro debba fare lo stesso:

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

Ho dovuto utilizzare una tabella generata da sottoquery nella prima query (di codifica) perché non sono riuscito a trovare alcun modo per convertire il valore originale ("TestData") nella sua rappresentazione in stringa esadecimale ("5465737444617461") da includere come argomento per xs: hexBinary () nell'istruzione XQuery.

Spero che questo aiuti qualcuno!


7
Quando si codifica, xs:base64Binary(sql:column("bin"))(senza la xs:hexBinarychiamata) funziona anche. Grande aiuto!
amphetamachine

3
Per supportare la codifica del testo Unicode, è necessario aggiungere "N" davanti a TestData : "SELECT CAST ( N " TestData "AS VARBINARY (MAX)) AS bin"
Kjetil Klaussen

Non ha funzionato per il testo Unicode ... SELECT CAST (N '' AS XML) .value ('xs: base64Binary (xs: hexBinary (sql: column ("bin")))', 'VARCHAR (MAX)') Codifica Base64 DA (SELEZIONA CAST (N 'मन्त्रीले उल्ट्याए सात छन्।' AS VARBINARIO (MAX)) AS bin) AS bin_sql_server_temp;
hsuk

3
@hsuk varchar non è compatibile con Unicode. Funziona bene se utilizzi invece nvarchar (max), ad esempio:SELECT CAST( CAST(N'' AS XML).value( 'xs:base64Binary("LgkoCU0JJAlNCTAJQAkyCUcJIAAJCTIJTQkfCU0JLwk+CQ8JIAA4CT4JJAkgABsJKAlNCWQJ")' , 'VARBINARY(MAX)' ) AS NVARCHAR(MAX) ) UnicodeEncoding ;
AlwaysLearning

7
Perché a volte le persone hanno bisogno di realizzare determinate cose nel software per ragioni che non puoi sempre prevedere ...?
mercurial

87

Il modo più semplice e breve che ho trovato per SQL Server 2012 e versioni successive è BINARY BASE64:

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

Per Base64 da stringere

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

(o nvarchar(max)per stringhe Unicode)


1
Questo è molto più semplice delle altre risposte e funziona altrettanto bene
sXe

3
qual è lo scopo di BINARY BASE64 nella prima riga? È necessario? Ho provato senza e sembra dare lo stesso risultato.
sabato

1
Il primo snippet mi ha dato un risultato diverso da quello che mi aspettavo; Ho cambiato "varbinary" in "varbinary (max)" e i caratteri mancanti sono
andati

3
Questa dovrebbe essere la risposta perché la risposta effettiva richiede stringhe letterali e non può accettare variabili come questa risposta.
Matthew

2
Per base64 in stringa, sto notando un significativo guadagno di prestazioni con .value ('data [1]', 'varbinary (max)') vice .value ('.', 'Varbinary (max)').
Geary M. McIver

25

Ecco una modifica alla risposta di Mercurial che utilizza anche la sottoquery sulla decodifica, consentendo l'uso di variabili in entrambi i casi.

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

22

Ecco il codice per le funzioni che faranno il lavoro

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

Esempio di utilizzo:

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

inserisci qui la descrizione dell'immagine


Generalmente utile. Questo non ha gestito caratteri come persiano e russo o emoji. ad esempio, سلام جیران o В России Base64 кодирует вас o ❤️💥🤪🦌🎅⛄🎄🤐🙈🙉🙊💩
Hunter-Orionnoir

Hai ragione. Gestisce dopo aver sostituito varchar a nvarchar
Oleg

8

Ho adorato la risposta di @ Slai. Ho dovuto apportare solo piccole modifiche alle battute che stavo cercando. Ho pensato di condividere ciò che ho ottenuto nel caso in cui aiutasse qualcun altro a imbattersi in questa pagina come ho fatto io:

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]

Per me, dovevo cambiare la seconda riga VARBINARYin VARBINARY(56), e poi ha funzionato.
Lee Grissom

Soluzione più breve, compatibile 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]

Questo è utile per codificare e decodificare.

Di Bharat J


0

Ho fatto uno script per convertire un hash esistente codificato in base64 in decimale, potrebbe essere utile:

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

-1

Puoi usare solo:

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

quindi dopo la codifica riceverai il testo "MjE4Nqk5"

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.