SQL Server研習錄(25)——sql server觸發器、instered表和deleted表知識詳解及示例分析


版權聲明

  • 本文原創作者:清風不渡
  • 博客地址:https://blog.csdn.net/WXKKang

一、創建測試數據

  首先我們創建測試數據以幫助我們學習本篇內容,共有兩張表:課程表(course)與學生表(student),其中學生表中的course_id字段爲course的外鍵,代碼如下:

USE [demo]

-- 創建course表
CREATE TABLE course(
	course_id varchar(50) PRIMARY KEY,
	course_name varchar(50)
)
GO

-- 創建student表
CREATE TABLE student(
	student_id varchar(50) PRIMARY KEY,
	student_name varchar(50),
	course_id varchar(50) FOREIGN KEY REFERENCES course(course_id)
)
GO

-- 插入數據
INSERT INTO course (course_id,course_name)
VALUES 
('C001','語文'),
('C002','數學'),
('C003','英語')
GO

INSERT INTO student (student_id,student_name,course_id)
VALUES
('S001','Lucy','C001'),
('S002','Jack','C002'),
('S003','Jane','C003'),
('S004','Jameson','C001')
GO

二、觸發器

1、基本知識

  爲了更好的強制業務規則和保證數據的完整性,sql server爲我們提供了兩種機制,它們分別是約束和觸發器,本篇我們就來學習觸發器,在觸發器中,我們可以查詢其他表,也可以包含複雜的Transact-SQL語句,並且可以將觸發器和觸發它的語句作爲可在觸發器內回滾的單個事務對待。如果檢測到嚴重錯誤(例如,磁盤空間不足),則整個事務即自動回滾
  說到這裏,我想到了數據庫中的另外一個東西——存儲過程,它們兩個真的是太像了,幾乎可以說存儲過程可以做什麼觸發器就可以做什麼,所以我們也可以把觸發器稱作是一種特殊的存儲過程,那麼,既然它是特殊的存儲過程,那它到底特殊在哪裏呢?觸發器與存儲過程最大的不同就是:它是與表事件(insert、delete、update)相關的存儲過程,它的執行既不是由程序調用的,也不是由手工調用的,而是由事件來觸發的,這就是它的神奇之處,比如當我們對一個表進行操作(insert、delete、update)時就會激活它執行,這就滿足了普通存儲過程所做不到的一些需求,是不是特別棒呢

2、觸發器的分類

  sql server包括三種常規類型的觸發器:DML觸發器、DDL觸發器和登錄觸發器

(1)DML觸發器

  當數據庫中表裏面的數據發生變化時,例如進行insert、update、delete操作時,如果我們對該表創建了對應的觸發器,那麼對應的觸發器在數據發生對應變化的時候就會自動執行。DML觸發器的主要作用爲:強制執行業務規則,以及擴展sql server的約束,默認值等。因爲約束只能約束同一個表中的數據,而我們在觸發器中可以執行任意sql語句,當然可以將其他表中想約束的任意字段與本表中相對應的字段聯合在一起來約束
  DML觸發器分爲:
  1、after觸發器(執行對應語句之後觸發):insert觸發器、update觸發器以及delete觸發器——只能定義在表上
  2、instead of(執行之前觸發):定義了instead of觸發器則表示並不執行其定義的操作(insert、update、delete)而僅是執行觸發器本身——可以在表上定義,也可以在視圖上定義

(2)DDL觸發器

  在sql server 2005中新增了DDL觸發器,它主要用於審覈與規範對數據庫表中表、觸發器、視圖等結構上的操作,比如在修改表、新增表、創建列、修改列等可以影響數據庫結構發生變化的時候執行的,我們主要是用它來記錄數據庫的修改過程,以及限制程序員對數據庫的修改,比如可以限制不允許刪除某些指定的表等

(3)登錄觸發器

  登錄觸發器是爲了響應Login事件而激發的存儲過程,與sql server示例建立用戶會話時將引發此事件,登錄觸發器將在登錄的身份驗證階段完成之後且用戶會話實際建立之前激發。因此,來自觸發器內部且通常將到達用戶的所有信息(例如錯誤消息和來自print語句的消息)會傳送到sql server錯誤日誌。如果身份驗證失敗,將不再激發登錄觸發器

3、instered表和deleted表

  觸發器有兩個特殊的表:instered表和deleted表,這兩張是邏輯表也是虛表。由系統在內存中創建者兩張表,不會存儲在數據庫中。而且兩張表的都是隻讀的,只能讀取數據而不能修改數據。這兩張表的結果總是與被該觸發器應用的表的結構相同,當觸發器完成工作後,這兩張表就會被刪除。Inserted表的數據是插入或是修改後的數據,而deleted表的數據是更新前的或是刪除的數據,它們具體存儲的數據與對應的表數據操作如下:

表操作 Inserted邏輯表 Deleted邏輯表
新增記錄(insert) 存放增加的記錄
修改記錄(update) 存放更新後的記錄 存放更新前的記錄
刪除記錄(delete) 存放被刪除的記錄

  爲什麼我們在對錶中的數據執行更新記錄的時候,instered表和deleted表中都會有數據呢?因爲我們在對錶中數據進行更新的操作,實際上是先刪除這條記錄,然後在新增一條記錄,因爲這樣,所以instered表和deleted表中都會有數據

二、編寫觸發器及示例

  現在,我們就結合示例來學習一下觸發器的具體操作

1、創建觸發器

(1)基本語法

  創建觸發器的語法如下:

CREATE TRIGGER [觸發器名稱] ON [表名稱]
	FOR UPDATE -- 或DELETE、或INSERT
AS 
	--Transact-SQL(業務邏輯代碼)
(2)delete觸發器示例

  現在我們根據上面的測試數據來創建一個觸發器,已知student表中的course_id爲course表的外鍵,那麼我們要實現這樣一個需求,當學生表(student)中沒有學生學習某一門課程的時候,我們將這門課程自動刪除。這時,我們就需要創建一個delete觸發器,代碼如下:

-- 創建studnet表的觸發器
CREATE TRIGGER [dbo].[student_delete] ON [dbo].[student]
FOR DELETE

AS

DECLARE @course_id VARCHAR(50)
SELECT @course_id = course_id FROM deleted
IF EXISTS (SELECT 1 FROM student WHERE course_id = @course_id)
BEGIN
	PRINT 'student表中存在學習該課程的學生' 
END
ELSE
BEGIN
	PRINT 'student表中不存在學習該課程的學生' 
	DELETE course where course_id = @course_id
	PRINT 'course表中相關數據已刪除'
END

  現在我們對此觸發器做一個測試,我們從上面的測試數據知道,Lucy和Jameson都學習了語文這門課程(course_id爲“C001”),現在Lucy由於轉班去了別的班級,我們需要將此學生的信息刪除,代碼如下:

delete student where student_id = 'S001'

  執行結果如下:
在這裏插入圖片描述
  我們知道,有兩名學生學習了語文,現在一位同學不在這個班級了,但是還有一名學生在學習語文這門課程,按照我們的預想,course表中課程名爲語文的這條記錄不應該被刪除,現在我們來驗證我們的預想,執行以下代碼:

SELECT * FROM student
SELECT * FROM course

在這裏插入圖片描述
  我們可以看到Lucy的記錄刪掉了,但是語文這門課程還在,結果與我們預想的一樣
  後來,Jamson因爲考了七次都沒有考過語文,心灰意冷的連夜買站票離開了這個城市,我們需要將他的記錄也清除掉,代碼如下:

delete student where student_id = 'S004'

  執行結果如下:
在這裏插入圖片描述
  可以看出,課程表中相關的內容也被刪除掉了,我們可以驗證一下,查詢結果如下:
在這裏插入圖片描述
  確實,不僅刪除了student表中名爲Jamson的記錄,也刪除了course表中課程名爲語文的課程記錄,說明我們的觸發器滿足了我們的需求

(3)update觸發器示例

  我們首先給student表中添加任課教師列(course_teacherName),然後爲在表中的數據添加相關任課教師的名稱,代碼如下:

ALTER TABLE course
ADD course_teacherName varchar(50)
GO

UPDATE course SET course_teacherName =
CASE WHEN course_id = 'C002' THEN '邢道榮'
WHEN course_id = 'C003' THEN '潘鳳' END
GO

  現在我們有這樣一個需求,就是課程的任課教師不允許修改,那麼我們就需要創建一個對應的update觸發器,代碼如下:

-- 創建studnet表的觸發器
CREATE TRIGGER [dbo].[course_update] ON [dbo].[course]
FOR UPDATE

AS

IF (UPDATE(course_teacherName))
BEGIN
	raiserror('任課老師不允許修改!',16,1);
	rollback tran;
END

  創建好了之後,我們再來更新任課教師的內容,代碼如下:

UPDATE course SET course_teacherName = '許褚' WHERE course_id = 'C002'

  執行結果如下:
在這裏插入圖片描述
  可以看到,這個觸發器滿足了我們的需求

(4)insert觸發器示例

  需求,我們需要在course表中添加更新時間字段(update_time),當我們插入學生的時候,就要對相應的該課程的時間進行更新,代碼如下:

-- 爲course表添加字段
ALTER TABLE course
ADD update_time varchar(50)
GO
-- 創建student表的觸發器
CREATE TRIGGER [dbo].[course_insert] ON [dbo].[student]
FOR insert

AS

DECLARE @course_id varchar(50)
SELECT @course_id = course_id FROM inserted
UPDATE course SET update_time = CONVERT(VARCHAR(50),GETDATE(),21) WHERE course_id = @course_id
PRINT '相應課程的修改時間已更新'

  下面我們來測試一下,爲student表中新添加一個學生,代碼如下:

INSERT INTO student VALUES ('S004','張三','C003')

  執行結果如下:
在這裏插入圖片描述
  現在我們來看course表中對應字段是否發生更新,查詢結果如下:
在這裏插入圖片描述
  可以看到,course表中對應的字段發生了更新,滿足了我們的需求

2、修改觸發器

  修改觸發器我們既可以在SSMS管理工具中找到該表並展開,然後展開觸發器之後選中對應的觸發器右鍵單擊修改,這樣就可以修改,或者可以使用T-SQL代碼修改,只需將關鍵字CREATE改爲ALTER即可,代碼結構:

ALTER TRIGGER [觸發器名稱] ON [表名稱]
	FOR UPDATE -- 或DELETE、或INSERT
AS 
	--Transact-SQL(業務邏輯代碼)

3、刪除觸發器

  同樣,如果需要刪除觸發器我們也可以在SSMS管理工具中找到該觸發器,然後右鍵刪除即可,也可以使用T-SQL代碼實現刪除,代碼如下:

drop trigger 觸發器名稱

  還有像禁用、啓用等操作都可以通過SSMS管理工具去簡單的實現,大家不妨試試喲

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章