我正在研究Oracle和SQL Server之间的ETL过程(没有主键 - >没有事务复制),并使用MD5哈希来检测源数据库和目标数据库之间的差异。
这适用于数据属于前127个ASCII字符的记录。但是当有任何'扩展的ascii'*字符,例如½
,°
或©
时,SQL Server的HASHBYTES
函数会以非标准方式散列这些字符(即与Oracle的DBMS_CRYPTO.Hash
,.Net加密库等不同。
所以当我在Oracle中运行它时:
select rawtohex(
DBMS_CRYPTO.Hash (
UTL_I18N.STRING_TO_RAW ('°', 'AL32UTF8'),
2)
) from dual;
我得到:4723EB5AA8B0CD28C7E09433839B8FAE
。
当我在SQL Server中运行它时:
SELECT HASHBYTES('md5', '°');
我得到:EC655B6DA8B9264A7C7C5E1A70642FA7
当我运行这个C#代码时:
string password = "°";
// byte array representation of that string
byte[] encodedPassword = new UTF8Encoding().GetBytes(password);
// need MD5 to calculate the hash
byte[] hash = ((HashAlgorithm) CryptoConfig.CreateFromName("MD5")).ComputeHash(encodedPassword);
// string representation (similar to UNIX format)
string encoded = BitConverter.ToString(hash)
// without dashes
.Replace("-", string.Empty)
// make lowercase
.ToLower();
我得到4723EB5AA8B0CD28C7E09433839B8FAE
,即与Oracle和我使用的每个在线工具相同。
是否有针对此问题的基于SQL的解决方案,还是需要创建CLR存储过程并在那里散列数据?
*我意识到这个词有点争议
答案 0 :(得分:2)
截至目前,MS SQL Server中没有UTF-8支持。因此,在将源字符串切换到最常见的分母(在这种情况下为UTF-16(可能))之前,您的哈希值始终不同。
答案 1 :(得分:0)
我决定通过实现使用.Net加密库的CLR存储过程来解决SQL Server对扩展ASCII的处理问题:
using System;
using System.Security.Cryptography;
using System.Text;
using Microsoft.SqlServer.Server;
public class Functions
{
[SqlFunction]
public static string GetMD5Hash (string input)
{
var encodedPassword = new UTF8Encoding().GetBytes(input);
var hash = ((HashAlgorithm)CryptoConfig.CreateFromName("MD5")).ComputeHash(encodedPassword);
return BitConverter.ToString(hash).Replace("-", string.Empty);
}
}