需要 SQL 雪花中的服务器 HASHBYTES SHA1 等效输出

Need SQL Server HASHBYTES SHA1 equivalent output in snowflake

我需要一个 SQL 来自 Snowflake 的服务器等效 Hashbytes SHA1 输出

SQL 服务器:

select hashbytes('sha1',cast('214163915155286000' as varchar(18)))*1

select cast(hashbytes('sha1',cast('214163915155286000' as varchar(18))) as int)

SQL 服务器输出:

2143072043

我可以使用下面的方法从 snowflake 生成 hashbytes 输出,但现在我无法将它转换成数值

select to_char(to_binary(sha1('214163915155286000'), 'hex'), 'base64') as Result;

部分雪花输出:

N0VDrFqYkK+M2GPrfJjnRn+8rys=

Snowflake 的预期输出:

2143072043

仅供参考 - 我在此处尝试了 SQL 服务器代码

http://sqlfiddle.com/#!18/9eecb/150528

所以在 SQL 服务器中进行少量播放。

select '214163915155286000' as s,
    hashbytes('sha1', '214163915155286000') as h,
    cast(hashbytes('sha1', '214163915155286000') as int) as i
;

给出:

s, 214163915155286000
h, 0x374543AC5A9890AF8CD863EB7C98E7467FBCAF2B
i, 2143072043

所以我的 SQL 和你的一样,作为一个好的开始。

2143072043 转换为十六进制,我们得到 7FBCAF2B 这是散列的最后 4 个字节。

因此你想获得散列和截断的结果,我将 BITAND 实现,但上次我使用雪花 BIT 函数时,它们确实允许十六进制输入,所以不用键入 a相当清楚 0xFFffFFff 我们将使用那个 4294967295 的小数,因此这应该适合你:

select bitand(sha1('214163915155286000'), 4294967295);

非常感谢 Gokhan 的洞察力,登录雪花,并阅读 BITSHIFTLEFT/RIGHT 的手册。我们可以使用移位,但输出是 128 位数字,而不是 64 位,正如我假设的那样,为了正确扩展符号位,我们必须移位 96 位,这段代码显示有效:

SELECT  
    column1 as input,
    sha1(input) as sha1,
    right(sha1,8) as right8,
    to_number(right8,'XXXXXXXX') as int32,
    BITSHIFTRIGHT(BITSHIFTLEFT(int32,96),96) as result
FROM VALUES 
    ('214163915155286001'),
    ('214163915155286000')
ORDER BY 1;

给出输出:

INPUT SHA1 RIGHT8 INT32 RESULT
214163915155286000 374543ac5a9890af8cd863eb7c98e7467fbcaf2b 7fbcaf2b 2143072043 2143072043
214163915155286001 1911d3df794846fbc74e0e4cf29133459466e0e7 9466e0e7 2489770215 -1805197081

所以 SQL 的更紧凑和最后的块可以是:

BITSHIFTRIGHT(BITSHIFTLEFT(to_number(right(sha1(input),8),'XXXXXXXX'),96),96)

昨天我检查你的 post 时,我注意到 Ms SQL 服务器使用 SHA1 哈希的最后 8 位数字(正如 Simon 指出的那样),所以我写了这个查询:

select to_number(right( sha1('214163915155286000'), 8 ), 'XXXXXXXX' );

它按预期生成了 2143072043,但不幸的是,如果我们想模拟 SQL 女士服务器的行为,这还不够

如果转换'214163915155286001',上面的转换returns2489770215。如果我们在MsSQLServer中进行精确转换,则returns-1805197081。问题是,SQL 服务器女士将结果存储在“有符号整数”中。在 Snowflake 中,没有带符号的整数。整数与 NUMBER 同义。所以我们需要处理“signed”位。这就是我编写以下 UDF 的原因:

create or replace function convertMStoSF( SHA varchar  )
returns NUMBER
language SQL
as
$$
IFF( bitand( to_number(right( sha1( SHA ), 8 ), 'XXXXXXXX' ) , 2147483648 ) > 0,  
       - 2147483648 + bitand( 2147483647,  to_number(right( sha1( SHA ), 8 ), 'XXXXXXXX' )  ) ,
       to_number(right( sha1( SHA ), 8 ), 'XXXXXXXX' ) )
$$;

它获取最后 8 位数字,转换为数字,并检查有符号位。如果为 1,则计算有符号值。如果为 0,则直接 returns 数字。在UDF中,我使用了十进制表示而不是十六进制:

0x7FFFFFFF -> 2147483647
0x80000000 -> 2147483648

这里是一个测试结果的查询:

select '214163915155286000' A, convertMStoSF( A ), '214163915155286001' B, convertMStoSF( B );

+--------------------+--------------------+--------------------+--------------------+
|         A          | CONVERTMSTOSF( A ) |         B          | CONVERTMSTOSF( B ) |
+--------------------+--------------------+--------------------+--------------------+
| 214163915155286000 |         2143072043 | 214163915155286001 |        -1805197081 |
+--------------------+--------------------+--------------------+--------------------+

我不得不说我不确定它是否 100% 正确,因为我只用几个样本数字进行测试。