数据库学习之旅——实验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的主要内容,如果未能解决你的问题,请参考以下文章