利用SQL Server觸發器實現錶的歷史修改痕跡記錄
在很多應用程式開發中,需要記錄某些資料錶的歷史記錄或修改痕跡,以便日後出現數據錯誤時進行資料排查。這種業務需求,我們可以通過資料庫的觸發器來輕鬆實現歷史記錄功能。
本文以SQL Server 2005資料庫中的觸發器為例(因為手中的專案用的就是這個資料庫)
先簡單描述一下SQL Server觸發器。
SQL Server觸發器的inserted和deleted
SQL Server為每個觸發器都建立了兩個專用虛擬表:inserted表和deleted表。這兩個表由系統來維護,他們存在於記憶體中,而不是在資料庫中。這兩個表的結構總是與被該觸發器作用的表結構相同。觸發器執行完成後,與該觸發器相關的兩個表會被刪除(即在記憶體中銷燬)。
inserted表存放由執行insert或update語句而要想飆中插入的所有行;即:插入後或更新後的值。
deleted表存放由delete或update語句而要從表中刪除的所有行;即:刪除或更新錢的值。
SQL操作 | inserted表 | deleted表 |
---|---|---|
增加(insert)記錄 | 存放新增的記錄 | [不可用] |
修改(update)記錄 | 存放更新後的記錄 | 存放更新前的記錄 |
刪除(delete)記錄 | [不可用] | 存放被刪除的記錄 |
SQL Server觸發器的instead of和after
SQL Server提供了兩種觸發器:instead of和after觸發器。這兩種觸發器的區別在於他們被啟用的時機不同:
- instead of觸發器用於替代引用觸發器執行的sql語句。除表之外,instead of觸發器也可以用於檢視,用來擴充套件檢視可以支援更新操作。
- after觸發器在一個inserted、update或delete語句之後執行,進行約束檢查等動作都在after觸發器被啟用之前發生。after觸發器只能用於資料表中。
說(複製)了這麼多,是因為我們要實現的功能需要用到inserted虛擬表、deleted虛擬表和after觸發器。
實現方法
通過一個示例來演示具體的實現方法。
假設當前有一個表:產品表(product),欄位為“產品名(name)”、“產品描述(description)”、“單價(unit_cost)”和“生成日期(pub_time)”。
CREATE TABLE product(name VARCHAR(50),description VARCHAR(200),unit_cost MONEY,pub_time DATETIME)
GO
現在我們”上帝”的需求是:需要記錄product表發生資料變化(增、刪、改)時,記錄每次操作改動情況。
1.建立日誌表
需要建立一個產品日誌表(product_log)用來將記錄每次資料改動情況,我這裡直接在原資料表的結構上增加兩個欄位(在實際開發環境中,大家可以根據需求來設定日誌表的表結構),分別為sqlcomm和exectime;程式碼如下:
CREATE TABLE product_log(name VARCHAR(50),pub_time DATETIME,sqlcomm varchar(10),exectime datetime) GO
新增的兩個欄位sqlcomm和exectime分別記錄執行命令(insert、update和delete)和執行時間
2.增加觸發器
在產品表增加觸發器,其目的是為了記錄表資料發生改變時記錄到product_log中。
針對插入(insert)操作,增加名為tr_product_i的觸發器:
CREATE TRIGGER tr_product_i ON product AFTER INSERT AS if @@rowcount = 0 --為了避免佔用資源,當影響行數為0時,結束觸發器 return insert into product_log (name,description,unit_cost,pub_time,sqlcomm,exectime) select name,'insert',getdate() from inserted GO
針對更新(update)操作,增加名為tr_product_u的觸發器:
CREATE TRIGGER tr_product_u ON product AFTER UPDATE AS if @@rowcount = 0 --為了避免佔用資源,當影響行數為0時,結束觸發器 return /*更新前*/ insert into product_log (name,'update',getdate() from deleted /*更新後*/ insert into product_log (name,getdate() from inserted GO
針對刪除(delete)操作,增加名為tr_product_d的觸發器:
CREATE TRIGGER tr_product_d ON product AFTER DELETE AS if @@rowcount = 0 --為了避免佔用資源,當影響行數為0時,結束觸發器 return insert into product_log (name,'delete',getdate() from deleted GO
3.測試觸發器
插入(insert)測試
INSERT INTO product(name,pub_time) VALUES('逗比','這是一個逗比的測試資料',200.5,'1990-11-18') GO SELECT * FROM product SELECT * FROM product_log GO
更新(update)測試
UPDATE product SET unit_cost=250.0 WHERE name='逗比' GO SELECT * FROM product SELECT * FROM product_log GO
刪除(delete)測試
DELETE FROM product WHERE name='逗比' GO SELECT * FROM product SELECT * FROM product_log GO
好了這篇文章就介紹到這了,需要的朋友可以參考一下。