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ページ(具体的には「補足文字」セクション)を参照してください。