SQL总结-----触发器
概念
触发器是一种特殊类型的存储过程,不由用户直接调用。创建触发器时会对其进行定义,以便在对特定表或列作特定类型的数据修改时执行。
触发器可以查询其他表,而且可以包含复杂的 SQL 语句。 它们主要用于强制服从复杂的业务规则或要求。 例如,您可以根据客户当前的帐户状态,控制是否允许插入新订单。
触发器也可用于强制引用完整性,以便在多个表中添加、更新或删除行时,保留在这些表之间所定义的关系。
作用
1)触发器可通过数据库中的相关表实现级联更改;通过级联引用完整性约束可以更有效地执行这些更改。
2)触发器可以强制比用 CHECK 约束定义的约束更为复杂的约束。与 CHECK 约束不同,触发器可以引用其它表中的列。例如,触发器可以使用另一个表中的 SELECT 比较插入或更新的数据,以及执行其它操作,如修改数据或显示用户定义错误信息。
3)触发器还可以强制执行业务规则
4)触发器也可以评估数据修改前后的表状态,并根据其差异采取对策。
实际应用
尽管触发器有很多优点,但是在实际的项目开发中,特别是OOP思想的深入,触发器的弊端也逐渐突显,主要:
1、过多的触发器使得数据逻辑变得复杂
2、数据操作比较隐含,不易进行调整修改
3、触发器的功能逐渐在代码逻辑或事务中替代实现,更符合OO思想。
建议:
使用触发器需慎重。
语法
CREATE TRIGGER trigger_name
ON {table_name | view_name}
{FOR | After | Instead of } [ insert, update,delete ]
AS
sql_statement
触发器类型
SQL Server 包括两种常规类型的触发器:数据操作语言 (DML) 触发器和数据定义语言 (DDL) 触发器。 当INSERT、UPDATE 或 DELETE 语句修改指定表或视图中的数据时,可以使用 DML 触发器。 DDL 触发器激发存储过程以响应各种 DDL 语句,这些语句主要以CREATE、ALTER 和 DROP 开头。 DDL 触发器可用于管理任务,例如审核和控制数据库操作。
通常说的触发器就是DML触发器。
DML 触发器在 INSERT、UPDATE 和 DELETE 语句上操作,并且有助于在表或视图中修改数据时强制业务规则,扩展数据完整性。
在SQL Server2005后又增加了DDL触发器。
DDL 触发器将激发存储过程以响应事件。但与 DML 触发器不同的是,它们不会为响应针对表或视图的 UPDATE、INSERT 或 DELETE 语句而激发。相反,它们将为了响应各种数据定义语言 (DDL) 事件而激发。这些事件主要与以关键字 CREATE、ALTER 和 DROP 开头的 Transact-SQL 语句对应。执行 DDL 式操作的系统存储过程也可以激发 DDL 触发器。
DDL 触发器使用场合:
- 要防止对数据库架构进行某些更改。
- 希望数据库中发生某种情况以响应数据库架构中的更改。
- 要记录数据库架构中的更改或事件。
在这里我们只讲述DML触发器。DML触发器又分以下分类:
1、 After触发器
After触发器要求只有执行某一操作insert、update、delete之后触发器才被触发,且只能定义在表上。
1)insert触发器
2)update触发器
3)delete触发器
2、Instead of 触发器
Instead of 触发器表示并不执行其定义的操作(insert、update、delete)而仅是执行触发器本身。既可以在表上定义instead of触发器,也可以在视图上定义。
INSTEAD OF 触发器用来代替通常的触发动作,即当对表进行INSERT、UPDATE 或 DELETE 操作时,系统不是直接对表执行这些操作,而是把操作内容交给触发器,让触发器检查所进行的操作是否正确。如正确才进行相应的操作。因此,INSTEAD OF 触发器的动作要早于表的约束处理。
实例:
INSTEAD OF 触发器:
向表“计0261”插入数据时,检查学号是否存在于表“计026”中,如存在则进行插入操作,否则就不插入。
- CREATE TRIGGER [checkid] ON [dbo].[计0261]
- INSTEAD OF insert
- AS
- IF NOT EXISTS(SELECT * FROM 计026 WHERE 学号=(SELECT 学号 FROM INSERTED))
- BEGIN
- ROLLBACK TRANSACTION
- PRINT '要处理记录的学号不存在!'
- END
- ELSE
- BEGIN
- INSERT INTO 计0261 select * from inserted
- PRINT '已经成功处理记录!'
- END
AFTER 触发器:
对订货表设置 AFTER(FOR) 类型的 INSERT 触发器,用来在插入记录时自动将统计值计算到订货统计表中。
- CREATE TRIGGER [orderinsert] ON [dbo].[订货表]
- AFTER INSERT
- AS
- DECLARE @bookid int, @ordernum int, @num int
- SELECT @bookid = 书籍编号, @ordernum = 数量 FROM INSERTED
- SELECT @num = count(书籍编号) FROM 订货统计表 WHERE 书籍编号=@bookid
- IF @num = 0
- --未找到该书,插入记录
- INSERT INTO 订货统计表 VALUES(@bookid, @ordernum)
- ELSE
- --找到该书,更新记录
- UPDATE 订货统计表
- SET 总订货量 = 总订货量 + @ordernum WHERE 书籍编号 = @bookid
inserted与deleted对比
触发器有两个特殊的表:插入表(instered表)和删除表(deleted表)。这两张是逻辑表也是虚表。有系统在内存中创建者两张表,不会存储在数据库中。而且两张表的都是只读的,只能读取数据而不能修改数据。这两张表的结果总是与被改触发器应用的表的结构相同。当触发器完成工作后,这两张表就会被删除。Inserted表的数据是插入或是修改后的数据,而deleted表的数据是更新前的或是删除的数据。
对表的操作 |
Inserted逻辑表 |
Deleted逻辑表 |
增加记录(insert) |
存放增加的记录 |
无 |
删除记录(delete) |
无 |
存放被删除的记录 |
修改记录(update) |
存放更新后的记录 |
存放更新前的记录 |
具体应用
在触发器实际应用中,主要还是建立约束以及级联更新。在这里主要通过简单实例予以说明。
1、触发器新增
原理:
当触发INSERT触发器时,新的数据行就会被插入到触发器表和inserted表中。inserted表是一个逻辑表,它包含了已经插入的数据行的一个副本。inserted表包含了INSERT语句中已记录的插入动作。inserted表还允许引用由初始化INSERT语句而产生的日志数据。触发器通过检查inserted表来确定是否执行触发器动作或如何执行它。inserted表中的行总是触发器表中一行或多行的副本。
场景:增加学生信息时,要校验其年龄,暂定其年龄必须大于18,否则新增失败
作用:校验约束
具体实例:

--触发器新增:只允许录取18岁以上学生
IF OBJECT_ID (N'TRIGER_Students_Insert', N'tr') IS NOT NULL
DROP TRIGGER TRIGER_Students_Insert;
GO
CREATE TRIGGER TRIGER_Students_Insert
ON Students
FOR INSERT
AS
declare @age int
select @age=COUNT(Students.ID) FROM Students INNER JOIN inserted ON Students.ID =inserted.ID
PRINT @age
if(@age<18)
begin
raiserror('学生年龄必须要大于18哦',16,8)
rollback tran
end

执行insert:
INSERT INTO Students(ID,Name,Age,City,MajorID) VALUES(105,'李四',16,'BeiJing',11)
执行结果:
会直接异常,返回错误信息
消息 50000,级别 16,状态 8,过程 TRIGER_Students_Insert,第 10 行
学生年龄必须要大于18哦
消息 3609,级别 16,状态 1,第 1 行
事务在触发器中结束。批处理已中止。
2、触发器更新
原理:
可将UPDATE语句看成两步操作:即捕获数据前像(before image)的DELETE语句,和捕获数据后像(after image)的INSERT语句。当在定义有触发器的表上执行UPDATE语句时,原始行(前像)被移入到deleted表,更新行(后像)被移入到inserted表。
触发器检查deleted表和inserted表以及被更新的表,来确定是否更新了多行以及如何执行触发器动作。
可以使用IF UPDATE语句定义一个监视指定列的数据更新的触发器。这样,就可以让触发器容易的隔离出特定列的活动。当它检测到指定列已经更新时,触发器就会进一步执行适当的动作,例如发出错误信息指出该列不能更新,或者根据新的更新的列值执行一系列的动作语句。
场景:
专业信息ID修改,对应的学生信息中专业ID也相应进行修改
实例实现:

--更新触发器:更新专业ID时,同时更新学生的专业信息
IF OBJECT_ID (N'TRIGER_Majors_Update', N'tr') IS NOT NULL
DROP TRIGGER TRIGER_Majors_Update;
GO
CREATE TRIGGER TRIGER_Majors_Update
ON Majors
FOR UPDATE
AS
IF UPDATE(ID)
UPDATE Students Set MajorID=inserted.ID
FROM Students,deleted,inserted
WHERE Students.MajorID = deleted.ID

原始数据:
执行更新操作:
UPDATE Majors SET ID=12 WHERE ID=11
执行结果:
3、触发器删除
原理:
当触发DELETE触发器后,从受影响的表中删除的行将被放置到一个特殊的deleted表中。deleted表是一个逻辑表,它保留已被删除数据行的一个副本。deleted表还允许引用由初始化DELETE语句产生的日志数据。
使用DELETE触发器时,需要考虑以下的事项和原则:
- 当某行被添加到deleted表中时,它就不再存在于数据库表中;因此,deleted表和数据库表没有相同的行。
- 创建deleted表时,空间是从内存中分配的。deleted表总是被存储在高速缓存中。
- 为DELETE动作定义的触发器并不执行TRUNCATE TABLE语句,原因在于日志不记录TRUNCATE TABLE语句。
场景:学校某选修课取消。
处理逻辑:在删除课程的同时,需要删除该课程的选课信息。
触发器:

--删除触发器:删除课程时,同时删除该课程的选课信息
IF OBJECT_ID (N'TRIGER_Courses_Delete', N'tr') IS NOT NULL
DROP TRIGGER TRIGER_Courses_Delete;
GO
CREATE TRIGGER TRIGER_Courses_Delete
ON Courses
FOR DELETE
AS
DELETE SC
FROM SC,deleted
WHERE SC.CourseID = deleted.ID

原始数据:
执行课程删除操作:
DELETE FROM Courses WHERE ID=10
执行结果:
可以看到,删除课程的同时,选修课程10的选课记录也被删除。
4、Instead Of 触发器
用Instead Of触发器实现与实例3相同的功能,具体实现代码如下:

--Instead Of触发器:删除课程时,同时删除该课程的选课信息
IF OBJECT_ID (N'TRIGER_Courses_Instead_Delete', N'tr') IS NOT NULL
DROP TRIGGER TRIGER_Courses_Instead_Delete;
GO
CREATE TRIGGER TRIGER_Courses_Instead_Delete
ON Courses
Instead Of DELETE
AS
declare @courseId int
--获取要删除的课程ID
SELECT @courseId=ID FROM deleted
--删除选课信息
DELETE FROM SC WHERE CourseID = @courseId
--删除课程信息
DELETE FROM Courses WHERE ID=@courseId

执行删除:
--测试用例
DELETE FROM Courses WHERE ID=10
测试结果:
其测试结果与实例3相同。
本文测试用例脚本:

--数据准备
--学生信息表
IF OBJECT_ID (N'Students', N'U') IS NOT NULL
DROP TABLE Students;
GO
CREATE TABLE Students(
ID int primary key not null,
Name nvarchar(50),
Age int,
City nvarchar(50),
MajorID int
) --专业信息表
IF OBJECT_ID (N'Majors', N'U') IS NOT NULL
DROP TABLE Majors;
GO
CREATE TABLE Majors(
ID int primary key not null,
Name nvarchar(50)
) --课程表
IF OBJECT_ID (N'Courses', N'U') IS NOT NULL
DROP TABLE Courses;
GO
CREATE TABLE Courses(
ID int primary key not null,
Name nvarchar(50) not null
) IF OBJECT_ID (N'SC', N'U') IS NOT NULL
DROP TABLE SC;
GO
--选课表
CREATE TABLE SC(
StudentID int not null,
CourseID int not null,
Score int
) /*
基础数据
*/ --专业信息
DELETE FROM Majors
INSERT INTO Majors(ID,Name) VALUES(10,'法律')
INSERT INTO Majors(ID,Name) VALUES(11,'美学') --课程信息
DELETE FROM Courses
INSERT INTO Courses(ID,Name) VALUES (10,'太极拳')
INSERT INTO Courses(ID,Name) VALUES (11,'摄影入门')
INSERT INTO Courses(ID,Name) VALUES (12,'生命科学导论') --学生信息
DELETE FROM Students
INSERT INTO Students(ID,Name,Age,City,MajorID) VALUES(101,'Tom',20,'BeiJing',10)
INSERT INTO Students(ID,Name,Age,City,MajorID) VALUES(103,'李明',20,'BeiJing',11)
INSERT INTO Students(ID,Name,Age,City,MajorID) VALUES(104,'王涛',18,'ShangHai',11) --选课信息
DELETE FROM SC
INSERT INTO SC(StudentID,CourseID) VALUES(101,10)
INSERT INTO SC(StudentID,CourseID) VALUES(101,11)
INSERT INTO SC(StudentID,CourseID) VALUES(102,12) --触发器新增:只允许录取18岁以上学生
IF OBJECT_ID (N'TRIGER_Students_Insert', N'tr') IS NOT NULL
DROP TRIGGER TRIGER_Students_Insert;
GO
CREATE TRIGGER TRIGER_Students_Insert
ON Students
FOR INSERT
AS
declare @age int
select @age=COUNT(Students.ID) FROM Students INNER JOIN inserted ON Students.ID =inserted.ID
PRINT @age
if(@age<18)
begin
raiserror('学生年龄必须要大于18哦',16,8)
rollback tran
end --测试用例
INSERT INTO Students(ID,Name,Age,City,MajorID) VALUES(105,'李四',16,'BeiJing',11)
SELECT * FROM Students --更新触发器:更新专业ID时,同时更新学生的专业信息
IF OBJECT_ID (N'TRIGER_Majors_Update', N'tr') IS NOT NULL
DROP TRIGGER TRIGER_Majors_Update;
GO
CREATE TRIGGER TRIGER_Majors_Update
ON Majors
FOR UPDATE
AS
IF UPDATE(ID)
UPDATE Students Set MajorID=inserted.ID
FROM Students,deleted,inserted
WHERE Students.MajorID = deleted.ID --测试用例
UPDATE Majors SET ID=12 WHERE ID=11 SELECT * FROM Students
SELECT * FROM Majors --删除触发器:删除课程时,同时删除该课程的选课信息
IF OBJECT_ID (N'TRIGER_Courses_Delete', N'tr') IS NOT NULL
DROP TRIGGER TRIGER_Courses_Delete;
GO
CREATE TRIGGER TRIGER_Courses_Delete
ON Courses
FOR DELETE
AS
DELETE SC
FROM SC,deleted
WHERE SC.CourseID = deleted.ID --测试用例
DELETE FROM Courses WHERE ID=10 --执行结果
SELECT * FROM Students
SELECT * FROM Courses
SELECT * FROM SC --Instead Of触发器:删除课程时,同时删除该课程的选课信息
IF OBJECT_ID (N'TRIGER_Courses_Instead_Delete', N'tr') IS NOT NULL
DROP TRIGGER TRIGER_Courses_Instead_Delete;
GO
CREATE TRIGGER TRIGER_Courses_Instead_Delete
ON Courses
Instead Of DELETE
AS
declare @courseId int
--获取要删除的课程ID
SELECT @courseId=ID FROM deleted
--删除选课信息
DELETE FROM SC WHERE CourseID = @courseId
--删除课程信息
DELETE FROM Courses WHERE ID=@courseId --测试用例
DELETE FROM Courses WHERE ID=10 --执行结果
SELECT * FROM Students
SELECT * FROM Courses
SELECT * FROM SC

其他
关于raiserror可见:
SQL总结-----触发器的更多相关文章
- Oracle数据库编程:使用PL/SQL编写触发器
8.使用PL/SQL编写触发器: 触发器存放在数据缓冲区中. 触发器加序列能够实现自动增长. 在触发器中不能使用connit和rollback. DML触发器 ...
- sql server触发器的例子
发布:thebaby 来源:脚本学堂 [大 中 小] 本文介绍下,在sql server数据库中使用触发器的简单例子,有需要的朋友可以参考下,希望对你有一定的帮助. 原文地址:http:/ ...
- 15、SQL Server 触发器
SQL Server 触发器 触发器是一种特殊的存储过程,只有当试图用数据操作语言DML来修改数据时才会触发,DML包含对视图和表的增.删.改. 触发器分为DML触发器和DDL触发器,其中DML触发器 ...
- (转)SQL Server 触发器
SQL Server 触发器 触发器是一种特殊类型的存储过程,它不同于之前的我们介绍的存储过程.触发器主要是通过事件进行触发被自动调用执行的.而存储过程可以通过存储过程的名称被调用. Ø 什么是触发器 ...
- 自己写的sql server触发器练练--高手请您跳过吧
set ANSI_NULLS ONset QUOTED_IDENTIFIER ONgo ALTER TRIGGER [insertReplyToic] ON [dbo].[bbsReplyTopic] ...
- sql update 触发器 可获得被update的行的信息
类型:转载 sql update 触发器 可获得被update的行的信息,需要的朋友可以参考下. 复制代码 代码如下: create trigger TgName on tb for update ...
- (2.13)Mysql之SQL基础——触发器
(2.13)Mysql之SQL基础——触发器 关键词:Mysql触发器 1.一般形式 -- 0.查看触发器[1]SHOW TRIGGERS;[2]SELECT * FROM `information_ ...
- sql server 触发器详细应用
SQL Server 触发器 触发器是一种特殊类型的存储过程,它不同于之前的我们介绍的存储过程.触发器主要是通过事件进行触发被自动调用执行的.而存储过程可以通过存储过程的名称被调用. Ø 什么是触发 ...
- SQL server触发器中 update insert delete 分别给写个例子被。
SQL server触发器中 update insert delete 分别给写个例子以及解释下例子的作用和意思被, 万分感谢!!!! 主要想知道下各个语句的书写规范. INSERT: 表1 (ID, ...
- 在Sql Server触发器中判断操作是Insert还是Update还是Delete
在Sql Server触发器中判断操作是Insert还是Update还是Delete DECLARE @IsInsert bit, @IsUpdate bit, @IsDelete ...
随机推荐
- ubuntu14.04 64 位 vmware tools 问题
当提示说open-vm-tools版本太低时可以这样解决 1.sudo apt-get autoremove open-vm-dkms open-vm-tools --purge 2.安装vmware ...
- 无需写try/catch,也能正常处理异常
对于企业应用的开发者来说,异常处理是一件既简单又复杂的事情.说其简单,是因为相关的编程无外乎try/catch/finally+throw而已:说其复杂,是因为我们往往很难按照我们真正需要的策略来处理 ...
- sqlserver镜像相关资料
本文出处:http://blog.csdn.net/dba_huangzj/article/details/35995083 镜像(Mirroring) SQL Server镜像简介 计划搭建SQL ...
- myeclipse10.X以上的破解方法
破解补丁下载地址:http://pan.baidu.com/s/1dDzVP3z 本文使用的破解补丁对MyEclipse Standard/ Professional/ Blue/ Spring的10 ...
- python 多继承详解-乾颐堂
1 2 3 4 5 6 7 8 9 10 class A(object): # A must be new-style class def __init__(self): prin ...
- Linux ls命令详解-乾颐堂CCIE
ls命令用法举例: 例一:列出/home文件夹下的所有文件和目录的详细资料: 1 ls -l -R /home 命令参数之前要有一短横线“-”, 上面的命令也可以这样写: 1 ls -lR /ho ...
- Oracle VirtualBox 问题汇总
1.打开虚拟机时报硬盘UUID 已经存在:错误信息: Cannot register the hard disk 'F:\VirtualBox VMs\cl-11r2-rac2\cl-11r2-rac ...
- explain分析sql效率
Explain命令在解决数据库性能上是第一推荐使用命令,大部分的性能问题可以通过此命令来简单的解决,Explain可以用来查看SQL语句的执行效 果,可以帮助选择更好的索引和优化查询语句,写出更好的优 ...
- (3)WePHP控制器与模型
MVC的先进理念就是程序流程 数据库操作 模板制作三个流程分离 大M函数会把模型引入到当前控制器的方法中,注意这个"excel"对应M文件夹的excel.php 同时也是整个exc ...
- javascript总结41:表格全选反选,经典案例详解
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...