SQL Server研习录(25)——sql server触发器、instered表和deleted表知识详解及示例分析
- 版权声明
- 一、创建测试数据
- 二、触发器
- 1、基本知识
- 2、触发器的分类
- (1)DML触发器
- (2)DDL触发器
- (3)登录触发器
- 3、instered表和deleted表
- 二、编写触发器及示例
- 1、创建触发器
- (1)基本语法
- (2)delete触发器示例
- (3)update触发器示例
- (4)insert触发器示例
- 2、修改触发器
- 3、删除触发器
版权声明
- 本文原创作者:清风不渡
- 博客地址:
一、创建测试数据
首先我们创建测试数据以帮助我们学习本篇内容,共有两张表:课程表(course)与学生表(student),其中学生表中的course_id字段为course的外键,代码如下:
USE [demo]
-- 创建course表
CREATE TABLE course(
course_id varchar(50) PRIMARY KEY,
course_name varchar(50)
)
GO
-- 创建student表
CREATE TABLE student(
student_id varchar(50) PRIMARY KEY,
student_name varchar(50),
course_id varchar(50) FOREIGN KEY REFERENCES course(course_id)
)
GO
-- 插入数据
INSERT INTO course (course_id,course_name)
VALUES
('C001','语文'),
('C002','数学'),
('C003','英语')
GO
INSERT INTO student (student_id,student_name,course_id)
VALUES
('S001','Lucy','C001'),
('S002','Jack','C002'),
('S003','Jane','C003'),
('S004','Jameson','C001')
GO
二、触发器
1、基本知识
为了更好的强制业务规则和保证数据的完整性,sql server为我们提供了两种机制,它们分别是约束和触发器,本篇我们就来学习触发器,在触发器中,我们可以查询其他表,也可以包含复杂的Transact-SQL语句,并且可以将触发器和触发它的语句作为可在触发器内回滚的单个事务对待。如果检测到严重错误(例如,磁盘空间不足),则整个事务即自动回滚
说到这里,我想到了数据库中的另外一个东西——存储过程,它们两个真的是太像了,几乎可以说存储过程可以做什么触发器就可以做什么,所以我们也可以把触发器称作是一种特殊的存储过程,那么,既然它是特殊的存储过程,那它到底特殊在哪里呢?触发器与存储过程最大的不同就是:它是与表事件(insert、delete、update)相关的存储过程,它的执行既不是由程序调用的,也不是由手工调用的,而是由事件来触发的,这就是它的神奇之处,比如当我们对一个表进行操作(insert、delete、update)时就会激活它执行,这就满足了普通存储过程所做不到的一些需求,是不是特别棒呢
2、触发器的分类
sql server包括三种常规类型的触发器:DML触发器、DDL触发器和登录触发器
(1)DML触发器
当数据库中表里面的数据发生变化时,例如进行insert、update、delete操作时,如果我们对该表创建了对应的触发器,那么对应的触发器在数据发生对应变化的时候就会自动执行。DML触发器的主要作用为:强制执行业务规则,以及扩展sql server的约束,默认值等。因为约束只能约束同一个表中的数据,而我们在触发器中可以执行任意sql语句,当然可以将其他表中想约束的任意字段与本表中相对应的字段联合在一起来约束
DML触发器分为:
1、after触发器(执行对应语句之后触发):insert触发器、update触发器以及delete触发器——只能定义在表上
2、instead of(执行之前触发):定义了instead of触发器则表示并不执行其定义的操作(insert、update、delete)而仅是执行触发器本身——可以在表上定义,也可以在视图上定义
(2)DDL触发器
在sql server 2005中新增了DDL触发器,它主要用于审核与规范对数据库表中表、触发器、视图等结构上的操作,比如在修改表、新增表、创建列、修改列等可以影响数据库结构发生变化的时候执行的,我们主要是用它来记录数据库的修改过程,以及限制程序员对数据库的修改,比如可以限制不允许删除某些指定的表等
(3)登录触发器
登录触发器是为了响应Login事件而激发的存储过程,与sql server示例建立用户会话时将引发此事件,登录触发器将在登录的身份验证阶段完成之后且用户会话实际建立之前激发。因此,来自触发器内部且通常将到达用户的所有信息(例如错误消息和来自print语句的消息)会传送到sql server错误日志。如果身份验证失败,将不再激发登录触发器
3、instered表和deleted表
这两张表的结果总是与被该触发器应用的表的结构相同,当触发器完成工作后,这两张表就会被删除。Inserted表的数据是插入或是修改后的数据,而deleted表的数据是更新前的或是删除的数据,它们具体存储的数据与对应的表数据操作如下:
表操作 | Inserted逻辑表 | Deleted逻辑表 |
新增记录(insert) | 存放增加的记录 | 无 |
修改记录(update) | 存放更新后的记录 | 存放更新前的记录 |
删除记录(delete) | 无 | 存放被删除的记录 |
为什么我们在对表中的数据执行更新记录的时候,instered表和deleted表中都会有数据呢?因为我们在对表中数据进行更新的操作,实际上是先删除这条记录,然后在新增一条记录,因为这样,所以instered表和deleted表中都会有数据
二、编写触发器及示例
现在,我们就结合示例来学习一下触发器的具体操作
1、创建触发器
(1)基本语法
创建触发器的语法如下:
CREATE TRIGGER [触发器名称] ON [表名称]
FOR UPDATE -- 或DELETE、或INSERT
AS
--Transact-SQL(业务逻辑代码)
(2)delete触发器示例
现在我们根据上面的测试数据来创建一个触发器,已知student表中的course_id为course表的外键,那么我们要实现这样一个需求,当学生表(student)中没有学生学习某一门课程的时候,我们将这门课程自动删除。这时,我们就需要创建一个delete触发器,代码如下:
-- 创建studnet表的触发器
CREATE TRIGGER [dbo].[student_delete] ON [dbo].[student]
FOR DELETE
AS
DECLARE @course_id VARCHAR(50)
SELECT @course_id = course_id FROM deleted
IF EXISTS (SELECT 1 FROM student WHERE course_id = @course_id)
BEGIN
PRINT 'student表中存在学习该课程的学生'
END
ELSE
BEGIN
PRINT 'student表中不存在学习该课程的学生'
DELETE course where course_id = @course_id
PRINT 'course表中相关数据已删除'
END
现在我们对此触发器做一个测试,我们从上面的测试数据知道,Lucy和Jameson都学习了语文这门课程(course_id为“C001”),现在Lucy由于转班去了别的班级,我们需要将此学生的信息删除,代码如下:
delete student where student_id = 'S001'
执行结果如下:
我们知道,有两名学生学习了语文,现在一位同学不在这个班级了,但是还有一名学生在学习语文这门课程,按照我们的预想,course表中课程名为语文的这条记录不应该被删除,现在我们来验证我们的预想,执行以下代码:
SELECT * FROM student
SELECT * FROM course
我们可以看到Lucy的记录删掉了,但是语文这门课程还在,结果与我们预想的一样
后来,Jamson因为考了七次都没有考过语文,心灰意冷的连夜买站票离开了这个城市,我们需要将他的记录也清除掉,代码如下:
delete student where student_id = 'S004'
执行结果如下:
可以看出,课程表中相关的内容也被删除掉了,我们可以验证一下,查询结果如下:
确实,不仅删除了student表中名为Jamson的记录,也删除了course表中课程名为语文的课程记录,说明我们的触发器满足了我们的需求
(3)update触发器示例
我们首先给student表中添加任课教师列(course_teacherName),然后为在表中的数据添加相关任课教师的名称,代码如下:
ALTER TABLE course
ADD course_teacherName varchar(50)
GO
UPDATE course SET course_teacherName =
CASE WHEN course_id = 'C002' THEN '邢道荣'
WHEN course_id = 'C003' THEN '潘凤' END
GO
现在我们有这样一个需求,就是课程的任课教师不允许修改,那么我们就需要创建一个对应的update触发器,代码如下:
-- 创建studnet表的触发器
CREATE TRIGGER [dbo].[course_update] ON [dbo].[course]
FOR UPDATE
AS
IF (UPDATE(course_teacherName))
BEGIN
raiserror('任课老师不允许修改!',16,1);
rollback tran;
END
创建好了之后,我们再来更新任课教师的内容,代码如下:
UPDATE course SET course_teacherName = '许褚' WHERE course_id = 'C002'
执行结果如下:
可以看到,这个触发器满足了我们的需求
(4)insert触发器示例
需求,我们需要在course表中添加更新时间字段(update_time),当我们插入学生的时候,就要对相应的该课程的时间进行更新,代码如下:
-- 为course表添加字段
ALTER TABLE course
ADD update_time varchar(50)
GO
-- 创建student表的触发器
CREATE TRIGGER [dbo].[course_insert] ON [dbo].[student]
FOR insert
AS
DECLARE @course_id varchar(50)
SELECT @course_id = course_id FROM inserted
UPDATE course SET update_time = CONVERT(VARCHAR(50),GETDATE(),21) WHERE course_id = @course_id
PRINT '相应课程的修改时间已更新'
下面我们来测试一下,为student表中新添加一个学生,代码如下:
INSERT INTO student VALUES ('S004','张三','C003')
执行结果如下:
现在我们来看course表中对应字段是否发生更新,查询结果如下:
可以看到,course表中对应的字段发生了更新,满足了我们的需求
2、修改触发器
修改触发器我们既可以在SSMS管理工具中找到该表并展开,然后展开触发器之后选中对应的触发器右键单击修改,这样就可以修改,或者可以使用T-SQL代码修改,只需将关键字CREATE改为ALTER即可,代码结构:
ALTER TRIGGER [触发器名称] ON [表名称]
FOR UPDATE -- 或DELETE、或INSERT
AS
--Transact-SQL(业务逻辑代码)
3、删除触发器
同样,如果需要删除触发器我们也可以在SSMS管理工具中找到该触发器,然后右键删除即可,也可以使用T-SQL代码实现删除,代码如下:
drop trigger 触发器名称
还有像禁用、启用等操作都可以通过SSMS管理工具去简单的实现,大家不妨试试哟