Encodage Base64 dans SQL Server 2005 T-SQL

124

Je voudrais écrire une requête T-SQL où j'encode une chaîne en tant que chaîne Base64. Étonnamment, je ne trouve aucune fonction T-SQL native pour l'encodage Base64. Existe-t-il une fonction native? Sinon, quelle est la meilleure façon de faire l'encodage Base64 dans T-SQL?

Jacob
la source
1
Je me demande pourquoi les données doivent être stockées sous forme de chaîne base64. Il y a une bonne raison d'utiliser base64 sur http, à savoir qu'il garantit l'interopérabilité entre les systèmes qui ne prennent en charge que le jeu de caractères ASCII (et qui traitent toutes les données comme du texte). Vous pouvez facilement convertir un tableau d'octets en base 64 et vice versa, alors pourquoi ne pas stocker les données efficacement? J'ai même vu des gens stocker des chaînes de base64 dans des colonnes nvarchar, ce qui prend 275% de l'espace de varbinary, ce qui entraîne un gaspillage de disque, de RAM, de réseau, etc.
The Dag
9
Il s'agit de générer une chaîne base64, pas d'en stocker une.
Jacob

Réponses:

187

Je sais que cela a déjà été répondu, mais j'ai juste passé plus de temps que je ne veux l'admettre à proposer des instructions SQL sur une seule ligne pour accomplir cela, donc je les partagerai ici au cas où quelqu'un d'autre aurait besoin de faire de même:

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

J'ai dû utiliser une table générée par une sous-requête dans la première requête (codage) car je ne trouvais aucun moyen de convertir la valeur d'origine ("TestData") en sa représentation sous forme de chaîne hexadécimale ("5465737444617461") à inclure comme argument de xs: hexBinary () dans l'instruction XQuery.

J'espère que ça aidera quelqu'un!

mercuriel
la source
7
Lors de l'encodage, xs:base64Binary(sql:column("bin"))(sans l' xs:hexBinaryappel) fonctionne également. Grande aide!
amphétamachine
3
Pour prendre en charge l'encodage du texte Unicode, vous devez ajouter 'N' devant TestData : 'SELECT CAST ( N ' TestData 'AS VARBINARY (MAX)) AS bin'
Kjetil Klaussen
N'a pas fonctionné pour le texte 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 le
3
@hsuk varchar n'est pas compatible avec Unicode. Cela fonctionne très bien si vous utilisez nvarchar (max) à la place, par exemple:SELECT CAST( CAST(N'' AS XML).value( 'xs:base64Binary("LgkoCU0JJAlNCTAJQAkyCUcJIAAJCTIJTQkfCU0JLwk+CQ8JIAA4CT4JJAkgABsJKAlNCWQJ")' , 'VARBINARY(MAX)' ) AS NVARCHAR(MAX) ) UnicodeEncoding ;
AlwaysLearning
7
Parce que parfois les gens ont besoin d'accomplir certaines choses dans le logiciel pour des raisons que vous ne pouvez pas toujours prévoir ...?
mercurial
87

Le moyen le plus simple et le plus court que j'ai pu trouver pour SQL Server 2012 et supérieur est BINARY BASE64:

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

Pour Base64 à la chaîne

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

(ou nvarchar(max)pour les chaînes Unicode)

Slai
la source
1
C'est beaucoup plus simple que les autres réponses et fonctionne tout aussi bien
sXe
3
quel est le but de BINARY BASE64 dans la première ligne? Est-ce nécessaire? J'ai essayé sans et il semble donner le même résultat.
mattpm
1
Le premier extrait m'a donné un résultat différent de ce à quoi je m'attendais; J'ai changé "varbinary" en "varbinary (max)" et les caractères manquants se sont mis en place
Hraefn
3
Cela devrait être la réponse car la réponse réelle nécessite des chaînes littérales et ne peut pas accepter de variables comme cette réponse peut.
Matthew
2
Pour base64 à chaîne, je remarque un gain de perf significatif avec .value ('data [1]', 'varbinary (max)') vice .value ('.', 'Varbinary (max)').
Geary M. McIver
25

Voici une modification de la réponse de mercurial qui utilise également la sous-requête sur le décodage, permettant l'utilisation de variables dans les deux instances.

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
la source
22

Voici le code des fonctions qui feront le travail

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

Exemple d'utilisation:

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

entrez la description de l'image ici

Oleg
la source
Généralement utile. Cela ne traitait aucun caractère comme le persan et le russe, ni les emoji. par exemple, سلام جیران ou В России Base64 кодирует вас ou ❤️💥🤪🦌🎅⛄🎄🤐🙈🙉🙊💩
Hunter-Orionnoir
Vous avez raison. Il gère après avoir remplacé varchar par nvarchar
Oleg
8

J'ai adoré la réponse de @ Slai. Je n'ai eu qu'à apporter des modifications mineures aux monoplaces que je recherchais. J'ai pensé partager ce avec quoi je me suis retrouvé au cas où cela aiderait quelqu'un d'autre à tomber sur cette page comme je l'ai fait:

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
la source
Pour moi, j'avais besoin de changer la deuxième ligne VARBINARYen VARBINARY(56), puis cela a fonctionné.
Lee Grissom
Solution la plus courte, compatible avec 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]

Ceci est utile pour encoder et décoder.

Par Bharat J

Bharat J
la source
0

J'ai fait un script pour convertir un hachage existant encodé en base64 en décimal, cela peut être utile:

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

Vous pouvez utiliser uniquement:

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

puis après l'encodage, vous recevrez le texte 'MjE4Nqk5'

jasmintmp
la source