【发布时间】:2018-04-28 02:16:14
【问题描述】:
我从外部来源收到原始数据文件,需要对它们进行分析。我将文件加载到表中并将字段设置为 varchars,然后运行一个复杂的 SQL 脚本来进行一些自动分析。我一直试图解决的一个问题是:如何判断一列数据是否与同一个表中的 1 个或多个其他列重复?
我的目标是为每一列设置一个散列、校验和或类似的东西,以查看每一行中列的值按照它们进入的顺序。我有动态 SQL,它根据 INFORMATION_SCHEMA.COLUMNS 中列出的字段循环遍历每个字段(不同的表将具有可变数量的列),因此无需担心如何完成该部分。
我整天都在研究这个,但似乎找不到任何明智的方法来散列字段的每一行。 Google 和 StackOverflow 搜索返回如何对数据行执行各种操作,但我找不到太多关于如何在字段上垂直执行相同操作的信息。
所以,我考虑了 2 种可能性并遇到了 2 个障碍:
- HASHBYTES - 使用“FOR XML PATH”(或类似的)抓取每一行并在每行之间使用分隔符,然后使用 HASHBYTES 对长字符串进行哈希处理。不幸的是,这对我不起作用,因为我正在运行 SQL Server 2014,并且 HASHBYTES 限制为 8000 个字符的输入。 (我还可以想象,在具有数百万行、200 多列循环的表上,性能会很糟糕)。
- CHECKSUM + CHECKSUM_AGG - 获取每个值的 CHECKSUM,将其转换为整数,然后在结果上使用 CHECKSUM_AGG(因为 CHECKSUM_AGG 需要整数)。这看起来很有希望,但不考虑数据的顺序,在不同的行上返回相同的值。此外,发生碰撞的风险更高。
第二个看起来很有希望,但没有像我希望的那样工作......
declare @t1 table
(col_1 varchar(5)
, col_2 varchar(5)
, col_3 varchar(5));
insert into @t1
values ('ABC', 'ABC', 'ABC')
, ('ABC', 'ABC', 'BCD')
, ('BCD', 'BCD', NULL)
, (NULL, NULL, 'ABC');
select * from @t1;
select cs_1 = CHECKSUM(col_1)
, cs_2 = CHECKSUM(col_2)
, cs_3 = CHECKSUM(col_3)
from @t1;
select csa_1 = CHECKSUM_AGG(CHECKSUM([col_1]))
, csa_2 = CHECKSUM_AGG(CHECKSUM([col_2]))
, csa_3 = CHECKSUM_AGG(CHECKSUM([col_3]))
from @t1;
在最后一个结果集中,所有 3 列都返回相同的值:2147449198。
期望的结果:我的目标是编写一些代码,其中 csa_1 和 csa_2 带回相同的值,而 csa_3 带回不同的值,表明它是自己独特的集合。
【问题讨论】:
-
CHECKSUM 和 BINARY_CHECKSUM 函数是非常差的哈希函数;你最好使用 hashbytes(MD5)
-
@MitchWheat 这对我来说非常有用,因为我正在使用相同的功能。是什么让他们很穷?为什么要避免它?非常感谢
-
@JohnLBevan OP 还需要知道整个集合是否相同,而不仅仅是哪些行相同。请参阅下面的解决方案以获取单个列。
-
@PittsburghDBA 这应该是我给的:都一样:sqlfiddle.com/#!18/6cf94/1,不一样:sqlfiddle.com/#!18/6cf94/2
-
@JohnLBevan 不错。下次把它放在答案中:-)
标签: sql sql-server tsql hash sql-server-2014