数据库学习之旅——实验7

Posted Henry Zheng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据库学习之旅——实验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

运行结果请读者自试。

以上是关于数据库学习之旅——实验7的主要内容,如果未能解决你的问题,请参考以下文章

数据库学习之旅——实验3

数据库学习之旅——实验3

数据库学习之旅——实验2

数据库学习之旅——实验8

数据库学习之旅——实验8

数据库学习之旅——实验6