【问题标题】:Implementing GetHashCode for string in T-SQL在 T-SQL 中为字符串实现 GetHashCode
【发布时间】:2013-09-26 09:44:02
【问题描述】:

我想在 T-SQL 中创建一个标量函数,它类似于 Java 中的那些。

命令式语言的标准实现是:

int hash = 0;
for (int i = 0; i < length; i++)
{
    hash = 31*hash + value[i];
}
return hash;

我在 tsql 中实现这一点并不是那么好,从我的观点来看,在 t-sql 中编写命令式代码是应该避免的。我想这可以使用 CTE 来完成?请=)

另外,我可以让它总是积极的,即当结果超过整数最大值时,它会超过 0 而不是整数最小值?让我们假设可能的参数数量(我的解决方案中特殊类的数量)并不是很大。假设它永远不会超过 1000,所以我确信即使使用 uint 也可以避免在这里发生冲突。


PS:如果有人对我需要这个做什么感兴趣,我可以解释一下,也许你可以提出一个更好的解决方案。我有一个表,其中包含 integer 标识列和 varchar'TypeFullName'- 这是我们 C# 解决方案中类的全名。

我需要编写一个脚本,手动将 ID 设置为 TypeFullName 的函数依赖项(是的,打开 SET IDENTITY INSERT 选项)。这样我就可以计算 ID,如果我知道类型名称的话。我知道这听起来像是一个设计糟糕的系统,而且很可能是这样,但相信我,我现在必须这样做)

谢谢!

【问题讨论】:

    标签: c# sql sql-server tsql common-table-expression


    【解决方案1】:

    阅读我关于 CheckSum 与 Hashbytes 的文章。 (http://craftydba.com/?p=3005)

    它们是两个内置的 SQL Server 函数,它们会在给定值的情况下为您生成哈希键。一个比另一个更独特。

    如果您仍有疑问,请尽管提问。

    真诚的

    约翰

    www.craftydba.com

    PS:

    在转换为 int 或 big int 时会丢失精度。只需将其保存为 GUID(16 字节十六进制)。

    【讨论】:

    • 嗨!我考虑过使用 MD5,但我需要将输出限制为正整数。 =) 使用所描述的哈希码算法更容易 - 只需在每次迭代时执行hash = hash % (2^32),然后执行if (hash &gt; 2147483647) { hash-=2147483647; }。 (我猜是这样的......)
    • 而使用 MD5 哈希我什么都做不了,我该怎么办,例如,使用 convert(int, HashBytes('MD5', 'test1'))?它给了我-1574543990。
    • 添加到第一条评论:在这种情况下,我会从 long(sql-server 中的 bigint)开始,然后在返回之前将其转换为 int。
    • You are losing precision when casting to a int or big int. Just save it as a GUID (16 byte hex). 好吧,但我需要int,因为我的id 列是int
    【解决方案2】:

    我在internet 中找到了一个解决方案,并稍微更新了它以限制输出为正数:

    begin
    declare @h bigint
    set @h = 0
    select @h = (@h*31 + ascii(substring(@str,X.pos,1)))%4294967296
       from (select top(len(@str)) 
                 row_number() over (order by getdate()) as pos 
               from sys.all_objects) as X
    if @h >= 2147483647 set @h = @h - 2147483647
    return convert(int, @h)
    end;
    

    select top from sys.all_objects 真的很hacky,但是(((至少它有效。

    【讨论】:

    • 上面的 row_number() 是一个 TALLY 表。有关详细信息,请参阅 Jeff Moden。基本上它是要交叉的数字表。因此,您正在查看每个字符并应用转换。
    • 是的,我知道它是如何工作的,它只会列出值 1..n,所以它有点像迭代器。我的意思是它看起来像一个黑客)
    • 唯一的选择是创建一个表 [msdb].[dbo].[Tally] 并使用 1 M 行或您可能使用的最大迭代器加载它。将代码更改为 '(SELECT TOP(LEN(@str)) from [msdb].[dbo].[Tally]) as X'。 Tally 表应该比 WHILE 循环更快。但看起来确实很有趣,因为它引用了 sys.all_objects。 (黑客)
    • @CRAFTYDBA,感谢您的建议!如果您不介意,我会接受我的回答,因为该解决方案更符合我的要求,尽管您的变体也很有意义。我希望我能再投一个赞成票,但是......))
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-23
    • 1970-01-01
    • 2018-07-16
    • 1970-01-01
    • 1970-01-01
    • 2011-03-23
    相关资源
    最近更新 更多