【问题标题】:SqlServer Checksum in C#C#中的SqlServer校验和
【发布时间】:2013-09-18 16:28:24
【问题描述】:

我在 sql server 2008 R2 中使用 chechsum 函数,我想在 C# 应用程序中获得相同的 int 值。 c# 中是否有任何等效方法可以返回诸如 sql checksum 函数之类的值? 谢谢

【问题讨论】:

标签: c# sql-server checksum


【解决方案1】:

在 SQL Server 论坛上,page 上声明:

SQL Server 中内置的 CHECKUM 函数是建立在一系列 4 位左旋异或运算之上的。更多解释请参见post

我能够将 BINARY_CHECKSUM 移植到 c# 并且它似乎正在工作...稍后我将查看普通的 CHECKSUM...

private int SQLBinaryChecksum(string text)
{
    long sum = 0;
    byte overflow;
    for (int i = 0; i < text.Length; i++)
    {
        sum = (long)((16 * sum) ^ Convert.ToUInt32(text[i]));
        overflow = (byte)(sum / 4294967296);
        sum = sum - overflow * 4294967296;
        sum = sum ^ overflow;
    }

    if (sum > 2147483647)
        sum = sum - 4294967296;
    else if (sum >= 32768 && sum <= 65535)
        sum = sum - 65536;
    else if (sum >= 128 && sum <= 255)
        sum = sum - 256;

    return (int)sum;
}

【讨论】:

  • 这太棒了,似乎与文本配合得很好。但是,我有一个 varbinary(max) 来存储文件,并且我将这个函数更改为采用字节数组而不是字符串。它适用于文本文件,但不会为二进制文件返回相同的结果。有什么想法吗?
  • 如何实现它以使用像 CHECKSUM(col1, col2, col3) 这样的少数字符串?
  • 小心这个解决方案。如果 BINARY_CHECKSUM() 从可变宽度列读取,则它只读取前 255 个字符。当然你可以在上面的代码中模拟它,但是你的代码在尝试匹配 SQL 的值时必须意识到这一点(docs.microsoft.com/en-us/sql/t-sql/functions/…)。
【解决方案2】:

CHECKSUM 文档没有透露它是如何计算散列的。如果你想要一个可以在 T-SQL 和 C# 中使用的哈希,请从 HashBytes 支持的算法中选择

【讨论】:

  • 太糟糕了,我一直在寻找一种将字符串散列到 int 的有效方法(尽管有冲突)。
  • @Andres - String.GetHashCode() 会将一个字符串散列为一个 int,您可以将其从 SQLCLR 函数中公开以在您的数据库中使用
【解决方案3】:

T-SQL 文档没有指定 checksum() 在此之外使用什么算法:

CHECKSUM 在其参数列表上计算一个称为校验和的哈希值。 哈希值 旨在用于构建哈希索引。如果 CHECKSUM 的参数是列,并且 index 基于计算的 CHECKSUM 值构建,结果是哈希索引。这可以用于 对列进行相等性搜索。

不太可能计算 MD5 哈希,因为它的返回值(计算的哈希)是一个 32 位整数; MD5 哈希的长度为 128 位。

【讨论】:

  • 实际上 SQLServer 为校验和函数返回一个 int。 MD5 散列是通过 HASHBYTES 函数完成的,并返回一个 varbinary(它应该是 C# 函数的返回值)。我正在寻找也返回 int 的 C# 函数。
  • 你说得对,我仔细阅读了 MSDN 页面,并没有说明任何内容......建议使用 HASHBYTES 代替它实现各种哈希算法。
【解决方案4】:

如果您需要对 GUID 进行校验和,请将 dna2 的答案更改为:

private int SQLBinaryChecksum(byte[] text)

对于字节数组,来自 SQL 的值将与来自 C# 的值匹配。测试:

var a = Guid.Parse("DEAA5789-6B51-4EED-B370-36F347A0E8E4").ToByteArray();
Console.WriteLine(SQLBinaryChecksum(a));

vs SQL:

select BINARY_CHECKSUM(CONVERT(uniqueidentifier,'DEAA5789-6B51-4EED-B370-36F347A0E8E4'))

两个答案都是 -1897092103。

【讨论】:

    【解决方案5】:

    @Dan 的 BinaryChecksum 实现在 c# 中可以大大简化为

    int SqlBinaryChecksum(string text)
    {
        uint accumulator = 0;
        for (int i = 0; i < text.Length; i++)
        {
            var leftRotate4bit = (accumulator << 4) | (accumulator >> -4);
            accumulator = leftRotate4bit ^ text[i];
        }
        return (int)accumulator;
    }
    

    这也使算法在做什么更清楚。对于每个字符,一个 4 位 circular shift 然后是一个带有字符字节的异或

    【讨论】:

      猜你喜欢
      • 2016-07-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-08
      • 1970-01-01
      • 2021-08-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多