散列一个 SQL 行?
Posted
技术标签:
【中文标题】散列一个 SQL 行?【英文标题】:hash a SQL row? 【发布时间】:2012-06-25 08:56:35 【问题描述】:有没有办法对 SQL 表中的一行进行 md5sum 以检查是否有任何列被修改?
我想检查是否有任何特定列已更改与我保存在文本文件中的旧数据副本(我将在 C# 中 md5sum)。
编辑:只需 md5sum-ing 每一行
【问题讨论】:
您是对整行进行 MD5 处理,还是仅对文本文件进行 MD5 处理? 最好的方法是在你的表中使用ROWVERSION
column。如果行发生任何更改,SQL Server 将自动更新此列。
表格不会被修改,文本文件会。我希望我可以 md5sum 该行,然后将其与文件行进行比较。别担心,我会手动提取每一行并 md5sum 数据库行
这是如何通过 select 语句完成的:SELECT Pk1 ,ROW_NUMBER() OVER ( ORDER BY Pk1 ) 'RowNum' ,(SELECT hashbytes('md5', ( SELECT Pk1, Col2, Col3 FOR XML raw ))) 'HashCkSum' FROM [MySchema].[MyTable];
其中Pk1
是表的主键,ColX
是您要监视更改的列。这应该对 MS SQL Svr 2008/2012 有效。
【参考方案1】:
有CHECKSUM(*)
、BINARY_CHECKSUM(*)
和CHECKSUM_AGG
。他们像 checkum 一样执行 CRC32,但对于检测一行的更改来说,它应该绰绰有余(你说的是 40 亿分之一的假阴性碰撞机会)。
使用HASHBYTES
进行加密哈希需要您构造一个表示“行”的表达式。
【讨论】:
根据环境的不同,40 亿分之一的人仍然可以足够频繁地预期它最终可能会发生。此外,在某些环境中,这样的事件可能是灾难性的。我不知道 OP 的需求,但甚至 MS 都不建议不使用CHECKSUM()
来确定行更改?
@Dems:不知道 OP 需要我不能说 CHECKSUM 是否足够好。我不会仅仅因为*
的便利性很难与HASHBYTES
相提并论而忽略它。提出一个表示行以便进行散列的表达式并非易事,当您考虑架构更改时更是如此。
@Dems:但我同意在很多情况下,40 亿分之一的概率太高了。请记住,由于您将已知行与另一个已知行(base don PK)进行比较,因此不存在meet-in-the-middle 问题。如果误报导致世界末日灾难,那么唯一的解决方案是进行完整的逐字节比较,所有哈希根据定义容易发生冲突。
这些功能并不像 MSDN 中看起来那么好。如果输入相似,很容易发生 CHECKSUM 冲突。看看这里:link 另外,如果您使用 CHECKSUM_AGG 小心 - 它在引擎盖下使用 XOR,因此也很容易发生冲突。你可以在这里阅读:link我不会单独相信这些功能
两个警告:HASHBYTES 被限制为 8000 字节的输入,并且 CHECKSUM() 为正数和负数小数生成相同的值 - 即,如果 x 是 int CHECKSUM([other columns], x) 和CHECKSUM([other columns], -x) 会有所不同,但如果 x 是小数,它们将是相同的。【参考方案2】:
如果您有 SQL Server 2008 或更新版本,您可以使用:
SELECT HASHBYTES('SHA1', (SELECT TOP 1 * FROM dbo.Table FOR XML RAW))
或
SELECT
HASHBYTES('SHA1',(
SELECT *
FROM dbo.myTable as tableToHash
where tableToHash.myUniqueKey=myTable.myUniqueKey
FOR XML RAW
)) as rowSHA1
from dbo.myTable;
【讨论】:
对我有用。我使用了 where 子句来限制当前行 有点晚了,但你能解释一下为什么这样的操作需要FOR XML XXX
吗?
@FlorianCastelain 因为您需要以某种方式将列放在一个文本行中,您也可以改用SELECT cast(column1 as nvarchar(max)) + cast(column2 as nvarchar(max)) + ... FROM dbo.myTable as tableToHash
【参考方案3】:
我必须开发一个解决方案来比较表结构并运行一个过程来导入表之间的差异。
我使用下面的代码来选择数据
--> 表结构
create table #table1 (
campo varchar(10)
,campo1 varchar(10)
)
create table #table2 (
campo varchar(10)
,campo1 varchar(10)
)
--> 插入值
insert into #table1 values ('bruno',1)
insert into #table1 values ('bruno',2)
insert into #table2 values ('bruno',1)
insert into #table2 values ('bruna',2)
--> 创建一个哈希列进行比较
select *,HASHBYTES('SHA1', (select z.* FOR XML RAW)) as hash
into #compare1
from #table1 z
select *,HASHBYTES('SHA1', (select k.* FOR XML RAW)) as hash
into #compare2
from #table2 k
--> 检查有什么不同的行
select * from #compare1 a
full outer join #compare2 b on a.hash = b.hash
where ( a.hash is null or b.hash is null )
也许这对需要同样东西的人有用 查找上面解释的代码here
【讨论】:
【参考方案4】:获取所有行,对每一列做md5,并与之前数据中对应列的md5进行比较。
【讨论】:
以上是关于散列一个 SQL 行?的主要内容,如果未能解决你的问题,请参考以下文章
有没有办法在oracle sql developer中对列的每个字段执行md5散列,并将结果散列存储在相应的列中(md5)