Sql server 检测SQL Server 2000表数据中的更改

Sql server 检测SQL Server 2000表数据中的更改,sql-server,hash,sql-server-2000,checksum,Sql Server,Hash,Sql Server 2000,Checksum,我定期检查某个查询(顺便说一句,该查询包含多个表),以便在上次检查后(每天一次)发生更改时向用户添加信息性消息 我尝试使用校验和+agg(binary\u checksum(*),但它没有帮助,所以帮助不大,因为我有以下情况(过于简化): 及 上述两种情况都会导致相同的校验和49,很明显数据已经更改 这不一定是一个简单的函数或简单的解决方案,但我需要某种方法来唯一识别SQL server 2000中的差异。校验和\u agg似乎只是将所有行的二进制校验和结果相加。尽管每一行都发生了变化,但两个校

我定期检查某个查询(顺便说一句,该查询包含多个表),以便在上次检查后(每天一次)发生更改时向用户添加信息性消息

我尝试使用
校验和+agg(binary\u checksum(*)
,但它没有帮助,所以帮助不大,因为我有以下情况(过于简化):

上述两种情况都会导致相同的校验和49,很明显数据已经更改


这不一定是一个简单的函数或简单的解决方案,但我需要某种方法来唯一识别SQL server 2000中的差异。

校验和\u agg似乎只是将所有行的二进制校验和结果相加。尽管每一行都发生了变化,但两个校验和之和没有变化(即17+32=16+33)。这并不是检查更新的标准,但我可以提出以下建议:

  • 不要使用
    checksum\u agg
    ,而是将校验和串接成一个分隔字符串,并按照
    从MyTable FOR XML PATH(“”)中选择binary\u checksum(*)+“,”的行比较字符串。要检查和存储的字符串要长得多,但进行误报比较的可能性要小得多
  • 不要使用内置的校验和例程,而是使用HASHBYTES在8000字节块中计算MD5校验和,并将结果异或在一起。这将为您提供一个更具弹性的校验和,尽管仍然不是防弹的(即,仍然有可能获得错误匹配,但可能性非常小)。我将粘贴我在下面编写的HASHBYTES演示代码
  • 最后一个选择,也是绝对的最后一个选择,是以XML格式实际存储表,并进行比较。这确实是唯一可以绝对确定没有错误匹配的方法,但不可扩展,并且需要存储和比较大量数据
  • 每种方法,包括您开始使用的方法,都有其优缺点,不同程度的数据大小和处理要求会影响准确性。根据您需要的精度级别,使用适当的选项。获得100%准确度的唯一方法是存储所有表数据

    或者,您可以向每个表添加一个date_modified字段,该字段使用after insert和update触发器设置为GetDate()。您可以从#test WHERE date\u modified>@date\u last\u checked
    中选择计数(*)。这是一种更常见的检查更新的方法。这种方法的缺点是无法跟踪删除

    另一种方法是创建一个修改过的表,带有table_name(VARCHAR)和is_modified(BIT)字段,每个要跟踪的表包含一行。使用insert、update和delete触发器,相关表的标志设置为True。当您运行计划时,检查并重置is_modified标志(在同一事务中)-从tblModified中选择@is_modified=is_modified,is_modified=0

    下面的脚本生成三个结果集,每个结果集对应于此响应前面的编号列表。在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
    
    ——创建测试表并填充它
    创建表#测试(
    f1 INT,
    f2 INT
    )
    插入#测试值(1,1)
    插入#测试值(2,0)
    插入#测试值(2,1)
    /*******************
    选择1
    *******************/
    从#XML路径测试(“”)中选择CAST(二进制校验和(*)作为VARCHAR)+’,'
    --声明:输入和输出MD5校验和(@in和@out)、输入字符串(@Input)和计数器(@i)
    声明@in-VARBINARY(16),@out-VARBINARY(16),@input-VARCHAR(MAX),@i-INT
    --将@input字符串初始化为表的XML转储
    --如果选择不使用MD5校验和,请将其用作比较字符串
    设置@input=(从#测试XML原始数据中选择*
    /*******************
    选择3
    *******************/
    选择@input
    --初始化计数器并输出MD5。
    设置@i=1
    设置@out=0x00000000000000
    而@i 8000然后8000 ELSE LEN(@input)-@i END))
    --将结果与输出进行异或运算
    设置@out=CAST(CAST(子字符串(@in,1,4)为INT)^CAST(子字符串(@out,1,4)为INT)为VARBINARY(4))+
    转换(转换(子字符串(@in,5,4)为INT)转换(子字符串(@out,5,4)为INT)为VARBINARY(4))+
    强制转换(子字符串(@in,9,4)为INT)强制转换(子字符串(@out,9,4)为INT)为VARBINARY(4))+
    强制转换(子字符串(@in,13,4)为INT)强制转换(子字符串(@out,13,4)为INT)为VARBINARY(4))
    设置@i=@i+8000
    结束
    /*******************
    选择2
    *******************/
    选择@out
    
    相关问题:尝试将
    时间戳
    /
    行版本
    列添加到基表中。不幸的是,“hashbytes”在SQL Server 2000中不是可识别的函数名。aah SQL2000。我错过了那个!我在这里找到了T-SQL的MD实现:。为疏忽道歉。我不相信有人真的写了这篇文章,感谢脚本和解决方案。请所有阅读此问题的人注意:我将问题查询中的
    checksum\u agg(binary\u checksum(*)替换为
    checksum\u agg(binary\u checksum(dbo.MD5)(cast(checksum(*)as nvarchar(4000‘‘)'))
    这实际上可以解决我的问题。。。
    select  checksum_agg(binary_checksum(*))
    from    
    (
        select  1 as id,
                0 as status
    
        union all
    
        select  2 as id,
                1 as status
    ) data
    
    -- 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