SQL SERVER 行级触发器(准)
2008-01-31 16:12
309 查看
SQL SERVER 准行级触发器
ⅰDeleted表和Inserted表
SQL SERVER只有表级和服务器级(相当)的触发器,在很多需要使用行级触发器的场合,很多同事都开始怀念使用Oracle的日子。但是事实上,我认为SQL SERVER这样做有它的理由(或难处),甚至于很多时候我会说,我们不需要精细到以行来触发的操作,因为我们往往要做的是处理哪些数据而不是哪条数据。不过如果您真的很需要,那么SQL SERVER提供了相应的手段足以让您实现类似的功能,并且应有更大的灵活性。对于SQL SERVER,一个添修删操作对应于确定的触发器只会作用一次,而不管在这个操作中有多少纪录受到了该次操作的影响,因为它是语句级的。但这并不意味着我们需要去遍历比较整个表才可以得知哪些记录发生了改变。在DML触发器开发中,我们可以通过Deleted表和Inserted表得到激活当前触发器的操作中那些受到影响的记录。
对于这两个表,我们可以这样理解。在一个添修删操作过程中,SQL引擎生成了这两个临时表。他把删除掉的数据暂时存储在Deleted表内,把要追加的数据存储在Inserted表内。而对于修改来说,我们把他理解为删除旧记录和加入新记录两个步骤,那么就是说他在两个表内分别存储了目标记录修改前后的数据。
想要检验这种猜测的合理性,我们不妨用下面的例子试试看。
USE [myTestDataBase]
-- 初始化
IF OBJECT_ID ('tbStudents', 'TABLE') IS NOT NULL
DROP TABLE [tbStudents]
GO
IF OBJECT_ID ('tbStudentsLog', 'TABLE') IS NOT NULL
DROP TABLE [tbStudentsLog]
GO
IF OBJECT_ID ('TR_StudentNameChanged', 'TR') IS NOT NULL
DROP TRIGGER TR_StudentNameChanged
GO
-- 学生表(包含学号和姓名两个字段)
CREATE TABLE [dbo].[tbStudents](
[StudentID] [nchar](10) COLLATE Japanese_CI_AS NOT NULL,
[StudentName] [nchar](10) COLLATE Japanese_CI_AS NULL,
CONSTRAINT [PK_tbStudents] PRIMARY KEY CLUSTERED ( [StudentID] ASC )
)
GO
-- 学生记录表(包含学号、现在姓名、曾用名三个字段)
CREATE TABLE [dbo].[tbStudentsLog](
[StudentID] [nchar](10) COLLATE Japanese_CI_AS NOT NULL,
[StudentNewName] [nchar](10) COLLATE Japanese_CI_AS NULL,
[StudentOldName] [nchar](10) COLLATE Japanese_CI_AS NULL,
CONSTRAINT [PK_tbStudentsLog] PRIMARY KEY CLUSTERED ( [StudentID] ASC )
)
GO
--定义[tbStudents]表被修改时的触发器
CREATE TRIGGER TR_StudentNameChanged
ON [tbStudents]
AFTER UPDATE
AS
--将被修改学生记录的修改前后的值存入学生记录
INSERT [tbStudentsLog]
SELECT [Inserted].[StudentID]
, [Inserted].[StudentName] AS [StudentNewName]
, [Deleted].[StudentName] AS [StudentOldName]
FROM [Inserted]
INNER JOIN [Deleted] ON [Deleted].[StudentID] = [Inserted].[StudentID]
WHERE NOT EXISTS(
SELECT *
FROM [tbStudentsLog]
WHERE [tbStudentsLog].[StudentID] = [Inserted].[StudentID])
GO
--加入两个学生
INSERT [dbo].[tbStudents] VALUES ('0000000001','小臭')
INSERT [dbo].[tbStudents] VALUES ('0000000002','小美')
--检查学生和学生纪录
SELECT * FROM [dbo].[tbStudents]
SELECT * FROM [dbo].[tbStudentsLog]
--修改一个学生的姓名
UPDATE [dbo].[tbStudents] SET [StudentName] = '大红花' WHERE [StudentID] = '0000000001'
--验证触发器地执行结果
SELECT * FROM [dbo].[tbStudents]
SELECT * FROM [dbo].[tbStudentsLog]
执行的结果:
我们把修改学生的姓名的SQL文的WHERE子句删除掉,替换成下面的语句再试试看
--修改所有学生的姓名
UPDATE [dbo].[tbStudents] SET [StudentName] = '全改掉'
执行后的结果是
ⅱ实现行级触发器
为了实现实现行级触发器,我们需要动用SQL游标,但是在触发器内一般的做法是不建议使用游标。因此这里只记录下这个思路,如果您真的要实现它,那么我想不是多么复杂。但是我想,一个程序员一旦应有了这种自主性,那么它往往就不会真的就只在这个触发器内模拟一个行级触发的功能吧。或许有一天我会真的需要它,那时候再来补上这段代码吧。
相关文章推荐
- 用SQL SERVER 触发器+作业 实现用户积分的透明管理
- sql server 触发器
- SQL Server 触发器
- SQL Server 中 触发器用法
- SQL Server 触发器
- 触发器三(行级DML触发器)
- ORACLE触发器 行级触发器
- sql server 创建触发器的语句格式
- sql server 2005学习笔记之触发器简介
- SQL Server 触发器
- 轻松掌握设计Sql Server触发器的原理
- SQL Server 2000 程序设计学习笔记--第九章 触发器
- SQL Server 开发之 使用触发器自动编号
- SQL Server 文档整理 - 3 触发器调用存储过程
- SQL SERVER 判断是否存在并删除某个数据库、表、视图、触发器、储存过程、函数
- 如何在SQL Server中使用触发器
- SQL Server 触发器
- SQL Server 触发器
- sql server 2008 触发器
- SQL Server查询数据库所有存储过程、触发器、索引信息SQL分享