数据库学习之旅——实验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

运行结果请读者自试。

  • 8
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值