Imr*_*zad 16 .net t-sql sql-server unicode encoding
我生成了一个md5哈希,如下所示:
DECLARE @varchar varchar(400)
SET @varchar = 'è'
SELECT CONVERT(VARCHAR(2000), HASHBYTES( 'MD5', @varchar ), 2)
Run Code Online (Sandbox Code Playgroud)
哪个输出:
785D512BE4316D578E6650613B45E934
Run Code Online (Sandbox Code Playgroud)
但是使用以下方法生成MD5哈希:
System.Text.Encoding.UTF8.GetBytes("è")
Run Code Online (Sandbox Code Playgroud)
产生:
0a35e149dbbb2d10d744bf675c7744b1
Run Code Online (Sandbox Code Playgroud)
C#.NET方法中的编码设置为UTF8,我假设varchar也是UTF8,任何关于我做错的想法?
Sol*_*zky 34
如果您正在处理NVARCHAR/ NCHARdata(存储为UTF-16 Little Endian),那么您将使用Unicode编码,而不是BigEndianUnicode.在.NET中,调用UTF-16,Unicode而其他Unicode编码由其实际名称引用:UTF7,UTF8和UTF32.因此,Unicode本身就是Little Endian相反的BigEndianUnicode.更新:请参阅最后关于UCS-2和补充字符的部分.
在数据库方面:
SELECT HASHBYTES('MD5', N'è') AS [HashBytesNVARCHAR]
-- FAC02CD988801F0495D35611223782CF
Run Code Online (Sandbox Code Playgroud)
在.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
Run Code Online (Sandbox Code Playgroud)
但是,这个问题属于VARCHAR/ CHARdata,它是ASCII,因此事情有点复杂.
在数据库方面:
SELECT HASHBYTES('MD5', 'è') AS [HashBytesVARCHAR]
-- 785D512BE4316D578E6650613B45E934
Run Code Online (Sandbox Code Playgroud)
我们已经在上面看到了.NET方面.从这些散列值来看,应该有两个问题:
HASHBYTES?ASCII,UTF7,和UTF8)所有符合HASHBYTES价值?有一个答案涵盖了两个问题:代码页.在"sqlteam"文章中进行的测试使用了"安全"的ASCII字符,这些字符在0到127范围内(就int /十进制值而言)在代码页之间没有变化.但是128 - 255范围 - 我们发现"è"字符 - 是扩展集,它确实因代码页而异(这是有意义的,因为这是拥有代码页的原因).
现在尝试:
SELECT HASHBYTES('MD5', 'è' COLLATE SQL_Latin1_General_CP1255_CI_AS) AS [HashBytes]
-- D1457B72C3FB323A2671125AEF3EAB5D
Run Code Online (Sandbox Code Playgroud)
这与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];
Run Code Online (Sandbox Code Playgroud)
返回:
TheChar TheASCIIvalue CharCP1255 TheASCIIvalueCP1255
è 232 ? 63
Run Code Online (Sandbox Code Playgroud)
一个??只是为了验证,运行:
SELECT CHAR(63) AS [WhatIs63?];
-- ?
Run Code Online (Sandbox Code Playgroud)
啊,所以Code Page 1255没有这个è角色,所以它被翻译为每个人的最爱?.但是,为什么在使用ASCII编码时,它与.NET中的MD5哈希值相匹配?可能是因为我们实际上并没有匹配哈希值è,而是匹配哈希值?:
SELECT HASHBYTES('MD5', '?') AS [HashBytesVARCHAR]
-- 0xD1457B72C3FB323A2671125AEF3EAB5D
Run Code Online (Sandbox Code Playgroud)
对.真正的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
Run Code Online (Sandbox Code Playgroud)
上面的查询返回(对我来说):
Latin1_General_100_CI_AS_SC 1252
Run Code Online (Sandbox Code Playgroud)
那么,让我们试试Code Page 1252:
System.Text.Encoding.GetEncoding(1252).GetBytes("è") // Matches HASHBYTES('MD5', 'è')
// 785D512BE4316D578E6650613B45E934
Run Code Online (Sandbox Code Playgroud)
呜啊!我们匹配VARCHAR使用默认SQL Server排序规则的数据:).当然,如果数据来自数据库或字段设置为不同的排序规则,那么GetEncoding(1252) 可能无效,您必须使用上面显示的查询找到实际匹配的代码页(代码页用于多个排序规则,因此不同的校对并不一定意味着不同的代码页.
要查看可能的代码页值以及它们所属的文化/区域设置,请在此处查看代码页列表(列表位于"备注"部分).
有关实际存储在NVARCHAR/ NCHARfields中的内容的其他信息:
可以存储任何UTF-16字符(2或4个字节),但内置函数的默认行为假定所有字符都是UCS-2(每个2字节),这是UTF-16的子集.从SQL Server 2012开始,可以访问一组支持4字节字符(称为补充字符)的Windows排序规则.使用其中一个结束的Windows排序规则(_SC为列指定或直接在查询中)将允许内置函数正确处理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];
Run Code Online (Sandbox Code Playgroud)
返回:
SupplementaryChar LEN DATALENGTH UNICODE LEFT HASHBYTES
2 4 55393 ? 0x7A04F43DA81E3150F539C6B99F4B8FA9
1 4 165739 0x7A04F43DA81E3150F539C6B99F4B8FA9
Run Code Online (Sandbox Code Playgroud)
如你所见,既不受影响DATALENGTH也HASHBYTES不受影响.有关详细信息,请参阅排序规则和Unicode支持的MSDN页面(特别是"补充字符"部分).
| 归档时间: |
|
| 查看次数: |
8617 次 |
| 最近记录: |