如何让SQL Server 2017及以下版本生成与Snowflake等数据库一致的拉丁字符SHA1值?
解决SQL Server与Snowflake非英文字符SHA1哈希匹配问题
问题的核心在于字符编码差异:SQL Server和Snowflake对非英文字符的默认编码方式不同,导致相同字符的字节表示不一样,最终SHA1哈希结果自然不匹配。
为什么会不一样?
- 在你的SQL Server环境中,
varchar使用的是数据库默认的非UTF-8代码页(比如常见的CP1252/Latin1),字符'á'被编码为单字节0xE1。 - Snowflake的默认
varchar采用UTF-8编码,'á'被编码为双字节0xC3A1。
两种编码的字节数组完全不同,SHA1哈希计算的是字节的哈希值,结果自然不同。
针对SQL Server 2017及以下版本的解决方案
我们需要让SQL Server先将nvarchar字符转换为UTF-8编码的字节数组,再计算SHA1哈希。由于2017及以下版本没有原生的UTF-8转换函数,可以借助XML的特性来实现:
-- 直接计算单个字符的SHA1(UTF-8编码) SELECT sys.fn_varbintohexsubstring(0, HASHBYTES('SHA1', CAST(CAST(N'á' AS XML).value('.', 'VARBINARY(MAX)') AS VARBINARY(MAX))), 1, 0) AS Utf8Sha1Result;
执行这条语句会返回2b9cc8d86a48fd3e4e76e117b1bd08884ec9691d,和Snowflake、Oracle等数据库的结果一致。
封装成自定义函数(方便复用)
如果需要频繁处理这类转换,可以创建一个自定义函数:
CREATE FUNCTION dbo.NvarcharToUtf8Bytes(@input NVARCHAR(MAX)) RETURNS VARBINARY(MAX) AS BEGIN -- 利用XML将NVARCHAR(UTF-16)转换为UTF-8字节 RETURN CAST(CAST(@input AS XML).value('.', 'VARBINARY(MAX)') AS VARBINARY(MAX)) END GO -- 使用函数计算SHA1 SELECT sys.fn_varbintohexsubstring(0, HASHBYTES('SHA1', dbo.NvarcharToUtf8Bytes(N'á')), 1, 0) AS Utf8Sha1Result;
原理说明
XML在处理字符时默认采用UTF-8编码,我们将nvarchar(UTF-16)转换为XML类型后,再提取其对应的二进制值,就得到了该字符的UTF-8编码字节数组,之后计算SHA1就能和其他使用UTF-8的数据库结果匹配。
内容的提问来源于stack exchange,提问作者Happygolucky
相关产品推荐
相关产品推荐

