2012-05-03 73 views
0

如果自上次檢查(每天一次)以來發生了某些變化,我會定期檢查某個查詢(通過該方式包含多個表)以向用戶添加信息性消息。檢測SQL Server 2000表數據中的更改

我試圖使它與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

相關問題:http://stackoverflow.com/questions/7362312/is-there-a-function-feature-in-sql-server-to-determine-if-a-table-has-any -recen –

+1

嘗試在您的基表中添加'timestamp' /'rowversion'列。 – wqw

回答

1

CHECKSUM_AGG似乎只是BIN​​ARY_CHECKSUM的結果相加爲所有行。儘管每一行都改變了,但兩個校驗和的總和還沒有(即17 + 32 = 16 + 33)。這是不是真的用於檢查更新的規範,但我能想出的建議如下:

  1. 而不是使用checksum_agg的,串聯校驗爲分隔字符串,字符串比較,沿行SELECT binary_checksum(*) + ',' FROM MyTable FOR XML PATH('')。要檢查和存儲的字符串要長得多,但誤判比較的可能性要小得多。
  2. 不使用內置校驗和例程,而是使用HASHBYTES計算8000字節塊中的MD5校驗和,並將結果與​​xor結合在一起。這會給你一個更有彈性的校驗和,雖然仍然不是防彈的(即它仍然有可能獲得錯誤的匹配,但是不太可能)。我將粘貼下面我寫的HASHBYTES演示代碼。
  3. 最後一個選項和絕對最後的手段是以XML格式實際存儲表格表並進行比較。這確實是您絕對可以確定沒有錯誤匹配的唯一方式,但不可擴展並涉及存儲和比較大量數據。

每種方法(包括您開始使用的方法)都有優點和缺點,不同程度的數據大小和處理要求與準確性有關。根據您需要的準確度級別,使用適當的選項。獲得100%準確性的唯一方法是存儲所有表格數據。

或者,您可以在每個表中添加一個date_modified字段,該表在插入和更新觸發器後使用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 
+0

+1,以及以XML格式存儲表格的想法。 –

+0

不幸的是,'hashbytes'不是SQL Server 2000中公認的函數名稱。 –

+1

Aaah SQL2000。我錯過了那一個!我在這裏找到了用於T-SQL的MD實現:http://www.hackchina.com/en/r/184114/MD5.sql__html。對疏忽表示歉意。 – Peter

相關問題