我定期检查某个查询(顺便提一下包含多个表格),如果上次检查后的某些内容发生了变化(每天一次),则向用户添加信息性消息。
我尝试使其与checksum_agg(binary_checksum(*))
一起使用,但它没有帮助,所以this question没有多大帮助,因为我有以下情况(过于简化):
select checksum_agg(binary_checksum(*))
from
(
select 1 as id,
1 as status
union all
select 2 as id,
0 as status
) data
和
select checksum_agg(binary_checksum(*))
from
(
select 1 as id,
0 as status
union all
select 2 as id,
1 as status
) data
上述两种情况都会产生相同的校验和,49,很明显数据已经改变。
这不一定是一个简单的函数或简单的解决方案,但我需要一些方法来唯一地识别SQL Server 2000中的差异。
答案 0 :(得分:1)
checksum_agg似乎只是为所有行添加binary_checksum的结果。虽然每行都有变化,但两个校验和的总和没有(即17 + 32 = 16 + 33)。这不是检查更新的常态,但我能提出的建议如下:
checksum_agg
,而是将校验和连接成一个分隔的字符串,并按照SELECT binary_checksum(*) + ',' FROM MyTable FOR XML PATH('')
的行比较字符串。要检查和存储的字符串要长得多,但误报率的可能性要小得多。每种方法,包括您开始使用的方法,都有利有弊,不同程度的数据大小和处理要求与准确性有关。根据所需的准确度级别,使用适当的选项。获得100%准确度的唯一方法是存储所有表数据。
或者,您可以向每个表添加date_modified字段,使用insert和update触发器后设置为GetDate()。你可以做SELECT COUNT(*) FROM #test WHERE date_modified > @date_last_checked
。这是检查更新的更常用方法。这个的缺点是无法跟踪删除。
另一种方法是使用table_name(VARCHAR)和is_modified(BIT)字段创建一个已修改的表,其中包含您要跟踪的每个表的一行。使用insert,update和delete触发器,相对表的标志设置为True。当您运行计划时,检查并重置is_modified标志(在同一事务中) - 沿SELECT @is_modified = is_modified, is_modified = 0 FROM tblModified
以下脚本生成三个结果集,每个结果集与此响应中较早的编号列表相对应。我已经在SELECT语句之前评论了哪个输出与哪个选项相对应。要查看输出是如何派生的,您可以在代码中向后工作。
-- Create the test table and populate it
CREATE TABLE #Test (
f1 INT,
f2 INT
)
INSERT INTO #Test VALUES(1, 1)
INSERT INTO #Test VALUES(2, 0)
INSERT INTO #Test VALUES(2, 1)
/*******************
OPTION 1
*******************/
SELECT CAST(binary_checksum(*) AS VARCHAR) + ',' FROM #test FOR XML PATH('')
-- Declaration: Input and output MD5 checksums (@in and @out), input string (@input), and counter (@i)
DECLARE @in VARBINARY(16), @out VARBINARY(16), @input VARCHAR(MAX), @i INT
-- Initialize @input string as the XML dump of the table
-- Use this as your comparison string if you choose to not use the MD5 checksum
SET @input = (SELECT * FROM #Test FOR XML RAW)
/*******************
OPTION 3
*******************/
SELECT @input
-- Initialise counter and output MD5.
SET @i = 1
SET @out = 0x00000000000000000000000000000000
WHILE @i <= LEN(@input)
BEGIN
-- calculate MD5 for this batch
SET @in = HASHBYTES('MD5', SUBSTRING(@input, @i, CASE WHEN LEN(@input) - @i > 8000 THEN 8000 ELSE LEN(@input) - @i END))
-- xor the results with the output
SET @out = CAST(CAST(SUBSTRING(@in, 1, 4) AS INT) ^ CAST(SUBSTRING(@out, 1, 4) AS INT) AS VARBINARY(4)) +
CAST(CAST(SUBSTRING(@in, 5, 4) AS INT) ^ CAST(SUBSTRING(@out, 5, 4) AS INT) AS VARBINARY(4)) +
CAST(CAST(SUBSTRING(@in, 9, 4) AS INT) ^ CAST(SUBSTRING(@out, 9, 4) AS INT) AS VARBINARY(4)) +
CAST(CAST(SUBSTRING(@in, 13, 4) AS INT) ^ CAST(SUBSTRING(@out, 13, 4) AS INT) AS VARBINARY(4))
SET @i = @i + 8000
END
/*******************
OPTION 2
*******************/
SELECT @out