sql >> データベース >  >> RDS >> Sqlserver

C#.NETmd5とは異なるTSQLmd5ハッシュ

    NVARCHARを扱っている場合 / NCHAR データ(UTF-16リトルエンディアンとして保存されます )、次に Unicodeを使用します BigEndianUnicodeではなくエンコーディング 。 .NETでは、UTF-16は Unicodeと呼ばれます 他のUnicodeエンコーディングは、実際の名前で参照されます:UTF7、UTF8、およびUTF32。したがって、 Unicode それ自体はLittleEndian BigEndianUnicodeとは対照的に 。 更新: UCS-2と補助文字については、最後のセクションを参照してください。

    データベース側:

    SELECT HASHBYTES('MD5', N'è') AS [HashBytesNVARCHAR]
    -- FAC02CD988801F0495D35611223782CF
    

    .NET側:

    System.Text.Encoding.ASCII.GetBytes("è")
    // D1457B72C3FB323A2671125AEF3EAB5D
    
    System.Text.Encoding.UTF7.GetBytes("è")
    // F63A0999FE759C5054613DDE20346193
    
    System.Text.Encoding.UTF8.GetBytes("è")
    // 0A35E149DBBB2D10D744BF675C7744B1
    
    System.Text.Encoding.UTF32.GetBytes("è")
    // 86D29922AC56CF022B639187828137F8
    
    System.Text.Encoding.BigEndianUnicode.GetBytes("è")
    // 407256AC97E4C5AEBCA825DEB3D2E89C
    
    System.Text.Encoding.Unicode.GetBytes("è")  // this one matches HASHBYTES('MD5', N'è')
    // FAC02CD988801F0495D35611223782CF
    

    ただし、この質問は VARCHARに関係します / CHAR データはASCIIであるため、状況は少し複雑になります。

    データベース側:

    SELECT HASHBYTES('MD5', 'è') AS [HashBytesVARCHAR]
    -- 785D512BE4316D578E6650613B45E934
    

    上記の.NET側はすでに表示されています。これらのハッシュ値から、2つの質問があるはずです:

    • なぜ何もしない そのうちのHASHBYTESと一致します 価値?
    • @Eric J.の回答にリンクされている「sqlteam.com」の記事に、そのうちの3つ( ASCII UTF7 、および UTF8 )すべて HASHBYTESと一致します 価値?

    両方の質問をカバーする1つの答えがあります:コードページ。 「sqlteam」の記事で行われたテストでは、コードページ間で変化しない0〜127の範囲(int / 10進値)の「安全な」ASCII文字を使用しました。ただし、「è」文字が見つかる128〜255の範囲は、拡張です。 コードページによって異なるセット(これがコードページを持つ理由であるため、これは理にかなっています)。

    今すぐお試しください:

    SELECT HASHBYTES('MD5', 'è' COLLATE SQL_Latin1_General_CP1255_CI_AS) AS [HashBytes]
    -- D1457B72C3FB323A2671125AEF3EAB5D
    

    これはASCIIと一致します ハッシュされた値(また、「sqlteam」の記事/テストでは0〜127の範囲の値が使用されたため、 COLLATEを使用しても変更は見られませんでした。 )。これで、 VARCHARに一致する方法がついに見つかりました。 / CHAR データ。よろしいですか?

    まあ、そうではありません。見てみましょう-私たちが実際にハッシュしていたものを見てください:

    SELECT 'è' AS [TheChar],
           ASCII('è') AS [TheASCIIvalue],
           'è' COLLATE SQL_Latin1_General_CP1255_CI_AS AS [CharCP1255],
           ASCII('è' COLLATE SQL_Latin1_General_CP1255_CI_AS) AS [TheASCIIvalueCP1255];
    

    返品:

    TheChar TheASCIIvalue   CharCP1255  TheASCIIvalueCP1255
    è       232             ?           63
    

    ?確認するために、次を実行します:

    SELECT CHAR(63) AS [WhatIs63?];
    -- ?
    

    ああ、コードページ1255にはèがありません 文字なので、みんなのお気に入りのとして翻訳されます 。しかし、ASCIIエンコーディングを使用しているときに、なぜそれが.NETのMD5ハッシュ値と一致したのでしょうか。 èのハッシュ値と実際に一致していなかった可能性があります 、しかし代わりにのハッシュ値と一致していました :

    SELECT HASHBYTES('MD5', '?') AS [HashBytesVARCHAR]
    -- 0xD1457B72C3FB323A2671125AEF3EAB5D
    

    うん。真のASCII文字セットはちょうどです 最初の128文字(値0〜127)。そして今見たように、è は232です。したがって、 ASCIIを使用します .NETでのエンコードはそれほど役に立ちません。 COLLATEも使用していませんでした T-SQL側で。

    .NET側でより良いエンコーディングを取得することは可能ですか?はい、コードページを指定できるEncoding.GetEncoding(Int32)を使用します。使用するコードページは、次のクエリを使用して検出できます( sys.columns を使用) リテラルまたは変数の代わりに列を操作する場合):

    SELECT sd.[collation_name],
           COLLATIONPROPERTY(sd.[collation_name], 'CodePage') AS [CodePage]
    FROM   sys.databases sd
    WHERE  sd.[name] = DB_NAME(); -- replace function with N'{db_name}' if not running in the DB
    

    上記のクエリは(私にとって)戻ります:

    Latin1_General_100_CI_AS_SC    1252
    

    それでは、コードページ1252を試してみましょう:

    System.Text.Encoding.GetEncoding(1252).GetBytes("è") // Matches HASHBYTES('MD5', 'è')
    // 785D512BE4316D578E6650613B45E934
    

    ウーフー! VARCHARに一致するものがあります デフォルトのSQLServer照合を使用するデータ:)。もちろん、データがデータベースまたは別の照合に設定されたフィールドからのものである場合は、 GetEncoding(1252) かもしれない 動作せず、上記のクエリを使用して実際に一致するコードページを見つける必要があります(コードページは多くの照合で使用されるため、別の照合が必ずしも必要ではありません 別のコードページを意味します。

    可能なコードページの値と、それらが関係する文化/ロケールを確認するには、ここにあるコードページのリストを参照してください(リストは「備考」セクションにあります)。

    NVARCHARに実際に保存されているものに関連する追加情報 / NCHAR フィールド:

    任意のUTF-16文字(2または4バイト)を格納できますが、組み込み関数のデフォルトの動作では、すべての文字がUTF-16のサブセットであるUCS-2(各2バイト)であると想定されています。 SQL Server 2012以降、補足文字と呼ばれる4バイト文字をサポートする一連のWindows照合にアクセスできるようになりました。 _SCで終わるこれらのWindows照合の1つを使用する 、列に指定するか、クエリで直接指定すると、組み込み関数で4バイト文字を適切に処理できるようになります。

    -- The database's collation is set to: SQL_Latin1_General_CP1_CI_AS
    SELECT  N'𨝫' AS [SupplementaryCharacter],
            LEN(N'𨝫') AS [LEN],
            DATALENGTH(N'𨝫') AS [DATALENGTH],
            UNICODE(N'𨝫') AS [UNICODE],
            LEFT(N'𨝫', 1) AS [LEFT],
            HASHBYTES('MD5', N'𨝫') AS [HASHBYTES];
    
    SELECT  N'𨝫' AS [SupplementaryCharacter],
            LEN(N'𨝫' COLLATE Latin1_General_100_CI_AS_SC) AS [LEN],
            DATALENGTH(N'𨝫' COLLATE Latin1_General_100_CI_AS_SC) AS [DATALENGTH],
            UNICODE(N'𨝫' COLLATE Latin1_General_100_CI_AS_SC) AS [UNICODE],
            LEFT(N'𨝫' COLLATE Latin1_General_100_CI_AS_SC, 1) AS [LEFT],
            HASHBYTES('MD5', N'𨝫' COLLATE Latin1_General_100_CI_AS_SC) AS [HASHBYTES];
    

    返品:

    SupplementaryChar   LEN   DATALENGTH   UNICODE   LEFT   HASHBYTES
    𨝫                  2     4             55393    �     0x7A04F43DA81E3150F539C6B99F4B8FA9
    𨝫                  1     4            165739    𨝫     0x7A04F43DA81E3150F539C6B99F4B8FA9
    

    ご覧のとおり、どちらの DATALENGTH も また、 HASHBYTES 影響を受けます。詳細については、照合とUnicodeのサポートに関するMSDNページ(具体的には「補足文字」セクション)を参照してください。



    1. 多くの場所でGETDATE()を使用する場合、変数を使用する方が良いですか?

    2. MySQLの階層クエリ

    3. Pythonカーソルを使用してストアドプロシージャから結果を返すことはできません

    4. MySQL5.7からMySQL8.0への移行-知っておくべきこと