利用SQL Server觸發(fā)器實(shí)現(xiàn)表的歷史修改痕跡記錄
在很多應(yīng)用程序開(kāi)發(fā)中,需要記錄某些數(shù)據(jù)表的歷史記錄或修改痕跡,以便日后出現(xiàn)數(shù)據(jù)錯(cuò)誤時(shí)進(jìn)行數(shù)據(jù)排查。這種業(yè)務(wù)需求,我們可以通過(guò)數(shù)據(jù)庫(kù)的觸發(fā)器來(lái)輕松實(shí)現(xiàn)歷史記錄功能。
本文以SQL Server 2005數(shù)據(jù)庫(kù)中的觸發(fā)器為例(因?yàn)槭种械捻?xiàng)目用的就是這個(gè)數(shù)據(jù)庫(kù))
先簡(jiǎn)單描述一下SQL Server觸發(fā)器。
SQL Server觸發(fā)器的inserted和deleted
SQL Server為每個(gè)觸發(fā)器都創(chuàng)建了兩個(gè)專(zhuān)用虛擬表:inserted表和deleted表。這兩個(gè)表由系統(tǒng)來(lái)維護(hù),他們存在于內(nèi)存中,而不是在數(shù)據(jù)庫(kù)中。這兩個(gè)表的結(jié)構(gòu)總是與被該觸發(fā)器作用的表結(jié)構(gòu)相同。觸發(fā)器執(zhí)行完成后,與該觸發(fā)器相關(guān)的兩個(gè)表會(huì)被刪除(即在內(nèi)存中銷(xiāo)毀)。
inserted表存放由執(zhí)行insert或update語(yǔ)句而要想飆中插入的所有行;即:插入后或更新后的值。
deleted表存放由delete或update語(yǔ)句而要從表中刪除的所有行;即:刪除或更新錢(qián)的值。
SQL操作 | inserted表 | deleted表 |
---|---|---|
增加(insert)記錄 | 存放新增的記錄 | [不可用] |
修改(update)記錄 | 存放更新后的記錄 | 存放更新前的記錄 |
刪除(delete)記錄 | [不可用] | 存放被刪除的記錄 |
SQL Server觸發(fā)器的instead of和after
SQL Server提供了兩種觸發(fā)器:instead of和after觸發(fā)器。這兩種觸發(fā)器的區(qū)別在于他們被激活的時(shí)機(jī)不同:
- instead of觸發(fā)器用于替代引用觸發(fā)器執(zhí)行的sql語(yǔ)句。除表之外,instead of觸發(fā)器也可以用于視圖,用來(lái)擴(kuò)展視圖可以支持更新操作。
- after觸發(fā)器在一個(gè)inserted、update或delete語(yǔ)句之后執(zhí)行,進(jìn)行約束檢查等動(dòng)作都在after觸發(fā)器被激活之前發(fā)生。after觸發(fā)器只能用于數(shù)據(jù)表中。
說(shuō)(復(fù)制)了這么多,是因?yàn)槲覀円獙?shí)現(xiàn)的功能需要用到inserted虛擬表、deleted虛擬表和after觸發(fā)器。
實(shí)現(xiàn)方法
通過(guò)一個(gè)示例來(lái)演示具體的實(shí)現(xiàn)方法。
假設(shè)當(dāng)前有一個(gè)表:產(chǎn)品表(product),字段為“產(chǎn)品名(name)”、“產(chǎn)品描述(description)”、“單價(jià)(unit_cost)”和“生成日期(pub_time)”。
CREATE TABLE product(name VARCHAR(50),description VARCHAR(200),unit_cost MONEY,pub_time DATETIME)
GO
現(xiàn)在我們”上帝”的需求是:需要記錄product表發(fā)生數(shù)據(jù)變化(增、刪、改)時(shí),記錄每次操作改動(dòng)情況。
1.創(chuàng)建日志表
需要?jiǎng)?chuàng)建一個(gè)產(chǎn)品日志表(product_log)用來(lái)將記錄每次數(shù)據(jù)改動(dòng)情況,我這里直接在原數(shù)據(jù)表的結(jié)構(gòu)上增加兩個(gè)字段(在實(shí)際開(kāi)發(fā)環(huán)境中,大家可以根據(jù)需求來(lái)設(shè)置日志表的表結(jié)構(gòu)),分別為sqlcomm和exectime;代碼如下:
CREATE TABLE product_log(name VARCHAR(50),description VARCHAR(200),unit_cost MONEY,pub_time DATETIME,sqlcomm varchar(10),exectime datetime) GO
新增的兩個(gè)字段sqlcomm和exectime分別記錄執(zhí)行命令(insert、update和delete)和執(zhí)行時(shí)間
2.增加觸發(fā)器
在產(chǎn)品表增加觸發(fā)器,其目的是為了記錄表數(shù)據(jù)發(fā)生改變時(shí)記錄到product_log中。
針對(duì)插入(insert)操作,增加名為tr_product_i的觸發(fā)器:
CREATE TRIGGER tr_product_i ON product AFTER INSERT AS if @@rowcount = 0 --為了避免占用資源,當(dāng)影響行數(shù)為0時(shí),結(jié)束觸發(fā)器 return insert into product_log (name,description,unit_cost,pub_time,sqlcomm,exectime) select name,description,unit_cost,pub_time,'insert',getdate() from inserted GO
針對(duì)更新(update)操作,增加名為tr_product_u的觸發(fā)器:
CREATE TRIGGER tr_product_u ON product AFTER UPDATE AS if @@rowcount = 0 --為了避免占用資源,當(dāng)影響行數(shù)為0時(shí),結(jié)束觸發(fā)器 return /*更新前*/ insert into product_log (name,description,unit_cost,pub_time,sqlcomm,exectime) select name,description,unit_cost,pub_time,'update',getdate() from deleted /*更新后*/ insert into product_log (name,description,unit_cost,pub_time,sqlcomm,exectime) select name,description,unit_cost,pub_time,'update',getdate() from inserted GO
針對(duì)刪除(delete)操作,增加名為tr_product_d的觸發(fā)器:
CREATE TRIGGER tr_product_d ON product AFTER DELETE AS if @@rowcount = 0 --為了避免占用資源,當(dāng)影響行數(shù)為0時(shí),結(jié)束觸發(fā)器 return insert into product_log (name,description,unit_cost,pub_time,sqlcomm,exectime) select name,description,unit_cost,pub_time,'delete',getdate() from deleted GO
3.測(cè)試觸發(fā)器
插入(insert)測(cè)試
INSERT INTO product(name,description,unit_cost,pub_time) VALUES('逗比','這是一個(gè)逗比的測(cè)試數(shù)據(jù)',200.5,'1990-11-18') GO SELECT * FROM product SELECT * FROM product_log GO
更新(update)測(cè)試
UPDATE product SET unit_cost=250.0 WHERE name='逗比' GO SELECT * FROM product SELECT * FROM product_log GO
刪除(delete)測(cè)試
DELETE FROM product WHERE name='逗比' GO SELECT * FROM product SELECT * FROM product_log GO
好了這篇文章就介紹到這了,需要的朋友可以參考一下。
相關(guān)文章
SQL Server 遠(yuǎn)程更新目標(biāo)表數(shù)據(jù)的存儲(chǔ)過(guò)程
這篇文章主要介紹了SQL Server 遠(yuǎn)程更新目標(biāo)表數(shù)據(jù)的存儲(chǔ)過(guò)程,適用于更新列名一致,主鍵為Int類(lèi)型,具體實(shí)例代碼大家參考下本文2018-05-05sql腳本查詢數(shù)據(jù)庫(kù)表,數(shù)據(jù),結(jié)構(gòu),約束等操作的方法
本文介紹了“sql腳本查詢數(shù)據(jù)庫(kù)表,數(shù)據(jù),結(jié)構(gòu),約束等操作的方法”,需要的朋友可以參考一下2013-03-03sql server通過(guò)pivot對(duì)數(shù)據(jù)進(jìn)行行列轉(zhuǎn)換的方法
這篇文章主要介紹了sql server通過(guò)pivot對(duì)數(shù)據(jù)進(jìn)行行列轉(zhuǎn)換的方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-05-05用SQL語(yǔ)句查詢數(shù)據(jù)庫(kù)中某一字段下相同值的記錄方法
本文要處理的事情實(shí)際上就是查詢數(shù)據(jù)庫(kù)表中某一字段值重復(fù)的記錄的方法2014-05-05SQLSERVER 語(yǔ)句交錯(cuò)引發(fā)的死鎖問(wèn)題案例詳解
這篇文章主要介紹了SQLSERVER 語(yǔ)句交錯(cuò)引發(fā)的死鎖研究,要解決死鎖問(wèn)題,個(gè)人感覺(jué)需要非常熟知各種隔離級(jí)別,尤其是 可提交讀 模式下的 CURD 加解鎖過(guò)程,這一篇我們就來(lái)好好聊一聊2023-02-02獲取SQL Server數(shù)據(jù)庫(kù)元數(shù)據(jù)的幾種方法
這篇文章主要介紹了獲取SQL Server數(shù)據(jù)庫(kù)元數(shù)據(jù)的幾種方法 ,需要的朋友可以參考下2015-08-08