1. 程式人生 > >資料庫學習之旅——實驗7

資料庫學習之旅——實驗7

本次實驗的目的是為了使讀者加深對資料完整性的理解,學會常見和使用觸發器。

觸發器原理解析:

1.觸發器概述

觸發器是SQL語言提供的一種維護資料完整性的工具。觸發器過程時由程式設計師給定,如一個和完整性控制動作有關的處理過程。當系統規定的出發條件發生時,給定的過程被呼叫。觸發條件是多種多樣的,例如:進入或退出程式的某層結構(如BLOCK,FORM 等);查詢、修改等操作發生之前或之後‘某個按鍵動作;TRIGGER過程呼叫(相當於子程式呼叫)。

觸發器是實施複雜完整性的特殊型別的儲存型別。觸發器不需要專門語句呼叫,對所保護資料進行修改時自動啟用,以防止對資料進行不正確,未授權或不一致的修改。

2.觸發器的型別及其具有的特殊表

一個觸發器值適用於一個表,每個表最多隻能有三個觸發器,分別是INSERT,UPDATE,DELETE觸發器。觸發器僅在實施資料完整性和處理業務規則時使用。

每個觸發器有兩個特殊的表,即插入表(INSERTED TABEL)和刪除表(DELETED TABLE)。這兩個表示邏輯表,並且這兩個表示由系統管理的,儲存在記憶體中,不是儲存在資料庫中。因此不允許直接對其修改,並且這兩個表的結構總是與被觸發器作用的表有相同的表結構。

3.三種觸發器的工作原理

INSERT觸發器:發向INSERTED表中插入一個新行的副本。然後檢查INSERTED表中的新行是否有效 ,確定是否要組織該插入操作。如果所插入的行中的值是有效的,則將該行插入到觸發器表。

UPDATE觸發器:先將原始資料行移到DELETED表中。然後將一個新行插入INSERTED表中。最後計算DELETED表和INSERTED表中的值以確定是否進行干預。

DELETE觸發器:將原始資料行移到DELETED表中,計算DELETED表中的值決定是否進行干預,如果不進行,那麼把資料行刪除。

4.SQL中建立觸發器的語法

GO

CREATE TRIGGER <觸發器> ON  <表明 | 檢視名>

[ WITH ENCRYPTIOM ]

{ FOR | AFTER | INSTEAD OF } { [ DELETE ] [ , ] [ INSERT ] [ , ] [ UPDATE ] }

[ WITH | APPEND ]

[ NOT FOR REPLICATION ]

AS <SQL語句組>

注意:建立觸發器的語句一定要是SQL批處理的第一局。

5.INSEAD OF 觸發器

在建立觸發器時指定INSTEAD OF 選項,表示資料庫將不執行觸發SQL語句二替換懲治性相應的觸發器操作。在表或檢視上,每個INSERT,UPDATE或DELETE語句最多可以定義一個INSTEAD OF 觸發器。然而,可以在每個具有INSTEAD OF 觸發器的檢視上定義檢視。INSTEAD OF 觸發器主要用於使用不能更新的檢視支援更新,並且允許選擇性地拒絕批處理中某些處分的操作。

INSTEAD OF 觸發器不能定義在WITH CHECK OPTION的可更新檢視上。同時,在含有使用DELETE或UPDATE級聯操作定義的外來鍵的表上也不能定義INSTEAD OF DELETE 和INSTEAD OF UPDATE觸發器。

6.觸發器和儲存過程的區別

(1)是否附屬於唯一的表。觸發器附屬於唯一的表,而儲存過程不附屬於任何的表。

(2)是否事件驅動。觸發器由事件驅動,而儲存過程由顯式的指令呼叫。

(3)是否有數量的限制,一般不允許建立太多的觸發器,對觸發器的數目有要求,而儲存過程沒有要求。

以下是本次實驗的練習與習題答案:(school表在此並未發出,請參考之前的練習)

USE SCHOOL
--2.3.4實驗練習
--(1)建立WORKER表,並自定義兩個約束U1以及U2,其中U1規定NAME欄位唯一,U2規定SAGE(級別)欄位的上限是28。
CREATE TABLE WORKER
(
NUMBER CHAR(5),
NAME CHAR(8) CONSTRAINT U1 UNIQUE,
SEX CHAR(1),
SAGE INT CONSTRAINT U2 CHECK(SAGE<=28),
DEAPARTMENT CHAR(20),
CONSTRAINT PK_WORKER PRIMARY KEY(NUMBER)
)
SELECT * FROM WORKER

--(2)在WORKER表中插入一條合法記錄。
INSERT INTO WORKER(NUMBER,NAME,SEX,SAGE,DEAPARTMENT) VALUES('00001','張三','M',20,'CS');
SELECT * FROM WORKER;


--(3)演示插入違反U2約束的例子,U2規定元組的SAGE屬性的值必須小於等於28.
INSERT INTO WORKER(NUMBER,NAME,SEX,SAGE,DEAPARTMENT) VALUES('00002','李四','M',29,'CS');
INSERT INTO WORKER(NUMBER,NAME,SEX,SAGE,DEAPARTMENT) VALUES('00002','李四','M',28,'CS');
SELECT * FROM WORKER;


--(4)去除U2約束。
ALTER TABLE WORKER DROP U2;


--(5)重新插入(3)中想要插入的資料,由於去除了U2約束,所以插入成功。
INSERT INTO WORKER(NUMBER,NAME,SEX,SAGE,DEAPARTMENT) VALUES('00003','王四','M',29,'IS');
SELECT * FROM WORKER;

--(6)建立規則RULE_SEX,規定插入或更新的值只能是M或F,並繫結到WORKER的SEX欄位。
GO
CREATE RULE RULE_SEX AS @VALUE IN ('F','M');
GO
EXEC SP_BINDRULE RULE_SEX, 'WORKER.[SEX]';


--(7)演示違反規則RULE_SEX的插入操作。
INSERT INTO WORKER VALUES('00004','王浩','1','25','CS');
INSERT INTO WORKER VALUES('00004','王浩','F','25','CS');
SELECT * FROM WORKER;


--2.3.4自我實踐
--(1)加入約束U3,令SAGE的值大於等於0.
ALTER TABLE WORKER ADD CONSTRAINT U3 CHECK(SAGE>=0);


--(2)加入規則R2,確保插入的記錄的SAGE值在1到100之間,並繫結到SAGE屬性上。
GO
CREATE RULE R2 AS @VALUE BETWEEN 1 AND 100
GO
EXEC SP_BINDRULE R2, 'WORKER.[SAGE]'; 
USE SCHOOL
--2.4.4實驗練習
--(1)為WORKER表建立觸發器T1,當插入或是更新表中資料時,保證所操作的記錄的SAGE值大於0.
--****首先依舊使用前一部落格中所用到的WORKER表
GO
CREATE TRIGGER T1 ON WORKER
FOR INSERT,UPDATE
AS
IF(SELECT SAGE FROM INSERTED)<1
BEGIN
	PRINT 'SAGE MUST BE A INTEGER MORE THAN ZERO! TRANSACION FAIL'
	ROLLBACK TRANSACTION
END


--(2)為WORKER表建立觸發器T2,禁止刪除編號為00001的CEO。
GO
CREATE TRIGGER T2 ON WORKER
FOR DELETE
AS
IF(SELECT NUMBER FROM DELETED)='00001'
BEGIN
	PRINT 'HE IS THE CEO!DELETE FAIL!'
	ROLLBACK TRANSACTION
END


--(3)WORKER表中的人員的編號是不可改變的,建立觸發器T3實現更新中編號的不可改變性。
GO
CREATE TRIGGER T3 ON WORKER
FOR UPDATE
AS
IF UPDATE(NUMBER)
BEGIN
	PRINT 'EVERY NUMBER CANNOT BE CHANGED!'
	ROLLBACK TRANSACTION
END


--(4)演示違反T1觸發器的約束的插入操作。
SELECT * FROM WORKER;
INSERT INTO WORKER VALUES('00005','李紅','F','-10','CS');


--(5)演示違反T1觸發器的約束的更新操作。
SELECT * FROM WORKER;
UPDATE WORKER SET SAGE= -7 WHERE NUMBER='00001';


--(6)演示違反T2觸發器的約束的刪除操作。
SELECT * FROM WORKER;
DELETE FROM WORKER WHERE NAME='張三';


--(7)演示違反T2觸發器的約束的更新操作。
SELECT * FROM WORKER;
UPDATE WORKER SET NUMBER='00007' WHERE SEX='F';


--(8)演示INSTEAD OF 觸發器在不可更新檢視上的運用。
CREATE VIEW STUDENTSCHOLARSHIP AS
SELECT ST.SID,ST.SNAME,ST.GRADE,SC.R_MONEY
FROM STUDENTS ST,SCHOLARSHIP SC
WHERE ST.SID=SC.STU_ID

INSERT INTO STUDENTSCHOLARSHIP VALUES('1000','JOHN','2003',1500)
--*****注:此時會出現錯誤,“檢視或函式'studentscholarship'不可更新,因為修改會影響多個基表。”針對該問題建立一個INSTEAD OF 觸發器即可
CREATE TRIGGER TRI_INS_STU_SCHOLARSHIP ON STUDENTSCHOLARSHIP
INSTEAD OF INSERT
AS
BEGIN
	SET NOCOUNT ON
	IF(NOT EXISTS
			(SELECT S.SID FROM STUDENTS S,INSERTED I
				WHERE S.SID=I.SID
			)
	)
	BEGIN
		INSERT INTO STUDENTS
			SELECT SID,SNAME,NULL,GRADE FROM INSERTED
		DECLARE @MAX_M_ID VARCHAR(10)
		SELECT @MAX_M_ID = MAX(M_ID) FROM SCHOLARSHIP
		INSERT INTO SCHOLARSHIP
			SELECT @MAX_M_ID + 1,SID,R_MONEY FROM INSERTED
	END
	ELSE PRINT '資料已經存在!'
END
--*****注:該觸發器是將原本一次性插入到STUDENTSCHOLARSHIP檢視的INSERT語句進行分解,從而避免了一次對多個基表進行操作。建立觸發器後再次嘗試更新檢視
INSERT INTO STUDENTSCHOLARSHIP VALUES('1000','JOHN','2003',1500)
SELECT * FROM STUDENTSCHOLARSHIP
SELECT * FROM STUDENTS WHERE SID = '1000'
SELECT * FROM SCHOLARSHIP WHERE STU_ID='1000'


針對以上練習,一下是自我練習題並附以答案:

--2.4.5自我實踐
--(1)建立一個在WORKER表上的觸發器T4,要求插入記錄的SAGE值必須必表中已記錄的最大SAGE值大。
GO
CREATE TRIGGER T4 ON WORKER
FOR INSERT 
AS
IF(SELECT SAGE FROM INSERTED)<=(SELECT MAX(SAGE) FROM WORKER)
BEGIN
	PRINT 'THE SAGE OF COUPLE MUST BE MORE THAN THE EXISTED COUPLES SAGE!'
	ROLLBACK TRANSACTION
END


--(2)建立一個在WORKER表上的觸發器T5,要求當更新一個記錄的時候,表中記錄的SAGE值要比老記錄的SAGE值大,因為一般工資級別只能升不能降。
GO
CREATE TRIGGER T5 ON WORKER
FOR UPDATE
AS
IF(SELECT SAGE FROM INSERTED)<=(SELECT SAGE FROM DELETED)
BEGIN
	PRINT 'THE SAGE OF NEW COUPLE MUST BE MORE THAN THE SAGE OF OLD COUPLE!'
	ROLLBACK TRANSACTION
END

執行結果請讀者自試。