数据的完整性是为了防止数据库中存在不符合语义的数据。
一种是在定义表时声明数据完整性,称为声明完整性。
另一种是在服务器端编写触发器来实现,称为过程完整性。完成比参照完整性约束和CHECK约束更复杂的数据约束。
1、触发器概述
触发器是一种特殊的存储过程,它是在执行某些特定的T-SQL语句时自动执行的一种存储过程。
不需要由用户调用执行,而是当用户对表中的数据进行UPDATE、INSERT或DELETE操作时自动触发执行的。
在 SQL Server 系统中,按照触发事件的不同可以把提供的触发器分成两大类型 : DML 触发器和 DDL 触发器。
1.DDL触发器
DDL 触发器当服务器或者数据库中发生数据定义语言(DDL)事件时将被调用。如果要执行以下操作,可以使用 DDL 触发器: 要防止对数据库架构进行某些更改 ;希望数据库中发生某种情况以响应数据库架构中的更改; 要记录数据库架构中的更改或者事件。
2.DML 触发器
DML 触发器是当数据库服务器中发生数据操作语言(DML)事件时要执行的操作。
通常所说的 DML 触发器主要包括三种:INSERT 触发器、UPDATE 触发器、DELETE 触发器。
DML 触发器可以查询其他表,还可以包含复杂的 Transact-SQL 语句。
SQL Server提供以下两种触发方式:
后触发:在触发操作(INSERT、 UPDATE或DELETE)执行完成,并处理过所有约束后激活触发器,这种方式称做后触发。如果触发操作违反约束条件,将导致事务回滚,这时就不会执行后触发器。但在视图上不能采用后触发方式定义触发器。
替代触发:当触发操作发生时,数据库引擎首先创建临时inserted表和deleted表,之后,SQL Server停止执行通常的操作,而转去执行替代触发器。
2、Deleted表和Inserted表
在触发器执行的时候,系统会产生两个临时表:inserted 表和deleted 表。
它们的结构和触发器所在的表的结构相同,SQL Server 自动创建和管理这些表。
可以使用这两个临时的驻留内存的表测试某些数据修改的效果及设置触发器操作的条件,然而不能直接对表中的数据进行更改。
在对具有触发器的表(触发器表)进行操作时,其操作过程:
执行INSERT操作,插入到触发器表中的新行被自动的插入到Inserted 表中。
执行DELETE操作,从触发器表中删除的行被自动的插入到Deleted 表中。
执行UPDATE操作,先从触发器表中删除旧行,然后再插入新行。其中被删除的旧行被插入到Deleted 表中,插入的新行被插入到Inserted 表中。
DELETED表存储DELETE和UPDATE语句所影响的行的副本。在执行DELETE或UPDATE语句时,行从触发器表中删除,并传输到DELETED表中。DELETED表和触发器表通常没有相同的行。
INSERTED表存储INSERT和UPDATE语句所影响的行的副本。在一个插入或更新操作中,新建行也同时添加到INSERTED表和触发器表中。INSERTED表中的行是触发器表中新行的副本。
3、定义触发器
建立触发器
CREATE TRIGGER 触发器名称
ON Table| view //是在其上执行触发器的表或视图,有时称为触发器表或触发器视图
{ FOR | AFTER | INSTEAD OF } //指定触发器触发的时机,其中 FOR 也创建 AFTER 触发器
{ [ INSERT ] [ , ] [ DELETE ] [ , ] [UPDATE ] } //是指定在表或视图上执行哪些数据修改语句时将触发触发器的关键字。必须至少指定一个选项。在触发器定义中允许使用以任意顺序组合的这些关键字。如果指定的选项多于一个,需用逗号分隔这些选项
AS SQL 语句 [ ... n ] //Sql_statement 指定触发器所执
行的 T-SQL 语句
After触发器在一个Insert,Update或Deleted语句之后执行,进行约束检查等动作都在After触发器被激活之前发生。After触发器只能用于表。
如果一个Insert﹑update或者delete语句违反了约束,那么After触发器不会执行,因为对约束的检查是在After触发器被激动之前发生的。所以After触发器不能超越约束。
Instead of触发器用于替代引起触发器执行的T-SQL语句。除表之外,Instead of 触发器也可以用于视图,用来扩展视图可以支持的更新操作。
Instead of 触发器可以取代激发它的操作来执行。它在Inserted表和Deleted表刚刚建立,其它任何操作还没有发生时被执行。因为Instead of 触发器在约束之前执行,所以它可以对约束进行一些预处理。
一个表或视图的每一个修改动作(insert,update和delete)都可以有一个instead of 触发器,一个表的每个修改动作都可以有多个After触发器。
1、INSTEAD OF 触发器——对数据增删改时,只执行触发器中的操作,而不执行( UPDATE、INSERT、DELETE )操作。
例子:Create trigger 学生表修改通知On studentinstead of insertAs Print '学生表发生了变化'select * from deletedselect * from insertedselect * from studentgo测试:Insert studentValues('201215016','刘席','男',16,'IS')2、AFTER触发器——数据增删改操作被临时存放,然后与触发器中的操作一起提交,也可以检查错误从而回退。相当于增删改操作与触发器中的操作构成一个事务。
例子:USE student
IF EXISTS (SELECT name FROM sysobjects
WHERE name = '学生表修改通知' AND type = 'TR')
DROP TRIGGER 学生表修改通知
GO
Create trigger 学生表修改通知
On student
For insert,update
As
Print '学生表发生了变化'
select * from deleted
select * from inserted
select * from student
go
--delete from 学生表where 姓名='刘席'
--DROP TRIGGER 学生表修改通知
插入记录Insert studentValues(‘20180016’,‘刘席’,‘男’,’20040205,‘信息安全')
定义一个触发器,如果在学生表中插入记录,则提示“欢迎新同学”。CREATE TRIGGER welcome_studentON studentAFTER INSERTAS PRINT '欢迎新同学!'GO创建一个名为 grade_warn 的触发器,当成绩大于100 时,就提示‘成绩不能大于100分’。然后执行 sp_helptrigger 列出表 SC 中触发器的相关信息。
USE SCC
IF OBJECT_ID('grade_warn','TR') IS NOT NULLDROP TRIGGER grade_warn;
GOCREATE TRIGGER grade_warnON SCFOR INSERT, UPDATE AS declare @gg intSELECT @gg=grade from insertedif @gg>100BEGINPRINT '成绩不能超过100分‘ROLLBACKENDEXEC sp_helptrigger SC.限制删除SC表中成绩不及格学生的修课记录。CREATE TRIGGER tri_del_gradeON SC FOR DELETEASIF EXISTS(SELECT * FROM DELETED WHERE Grade < 60)ROLLBACK 限制将SC表中不及格学生的成绩改为及格。create trigger tri_update_grade
on sc for update
as if update(grade)if exists(select * from inserted,deletedwhere inserted.sno=deleted.sno and inserted.grade>=60 and deleted.grade<60)begin print '不能将不及格的成绩改为及格'rollbackend学生退学了要自动删除学生的选课信息
CREATE TRIGGER t_delS ON S
instead of DELETE
AS delete from scfrom deletedwhere sc.sno=deleted.sno delete from sfrom deletedwhere s.sno=deleted.sno测试: delete from s where sno='95001'创建一个名为tri_Insert_S的触发器,测试该触发器的执行情况,并给出实验结果。当插入的新记录中Sage的值不是18至25之间的数值时,就激活该触发器,撤销该插入操作,并给出错误提示。
use SCC
go
create trigger tri_Insert_S on Student
after insert
as
if exists (select * from insertedwhere Sage>=18 and Sage<=25)print'添加成功!'
elsebegin print'无法添加!'rollback transactionend
go
insert into Student values(‘201205221','黄丽','女',26,'计算机')
insert into Student values(‘201205222’,’黄月英','女',20,'计算机')
select *
from Student
go创建一个名为tri_Update_SC的触发器,要求:(1)首先判断数据库中是否已经存在名为tri_Update_SC的触发器,如果存在,首先删除,再创建。(2)当试图修改SC表中的学生成绩时,给出不能随便修改成绩的信息提示。
use SCC
go
if exists(select name from sysobjectswhere name='tri_Update_SC' and type='TR')begin drop trigger tri_Update_SCend
else print'不存在该触发器,可新建。'
Go
create trigger tri_Update_SC on SC
after update
asif update(GRADE)beginprint'不能随意修改成绩!'rollback transactionend
goupdate SC
set GRADE=90
Go禁用tri_Update_SC触发器,并演示禁用该触发器后Update的执行情况。
use scc
go
alter table SC disable trigger tri_Update_SC
update SC
set Score='95'
where Sno='S1' and Cno='C3'
print'修改成功!'
select *
from SC
Go创建一个名为tri_Delete_C 的触发器,实现:删除一门课程时候,首先判断该课程有否有人选,如果有人选,则不能删除并通过测试数据验证该触发器的执行情况。use SCC
go
create trigger tri_Delete_C on Course
instead of delete
as
if(exists (select * from SC,deletedwhere SC.Cno=deleted.Cno))beginrollback transactionprint'该课程无法删除!'end
elsebegindelete from Course where Cno in( select Cno from deleted)end
go
delete from Course
where Cno='C1'
go
4、查看触发器
若要查看某一特定表上现有的触发器,使用存储过程:
sp_helptrigger 数据表名
若要查看已经建好的触发器代码。使用存储过程:
sp_helptext 触发器名
使用系统存储过程sp_help,sp_helptext,sp_helptrigger查看触发器相关信息。给出显示结果。
use SCC
go
exec sp_help 'tri_Insert_S'
exec sp_helptext 'tri_Insert_S'
exec sp_helptrigger 'S'
go
5、删除触发器
修改触发器语法格式:
ALTER TRIGGER 触发器名称
ON 表名
{ FOR | AFTER | INSTEAD OF }
{ [ INSERT ] [ , ] [ DELETE ] [ , ] [UPDATE ] }
AS SQL 语句 [ ... n ] 删除触发器语法格式:
DROP TRIGGER 触发器名 [ , ... n ]例:删除tri_grade触发器。
DROP TRIGGER tri_grade