今天做代码审查时,看见以下一段触发器的创建脚本,我们一起来分析一下
create trigger [trigger_puClassRoomType]
on [dbo].[puClassRoomType]
AFTER update
as
declare @roomname nvarchar(100),@roomnumber nvarchar(100)
select @roomname = TypeName,@roomnumber=TypeNumber from Inserted
begin
update ExamingClasses set TypeName=@roomname where TypeNumber=@roomnumber
update PlanNumTimePlace set ClassroomName=@roomname where Classroomnum=@roomnumber
end
go
书写这段代码的程序员可能对 1、SQLServer变量赋值 2、触发器Inserted表 这两个概念模糊,首先我们谈谈Inserted表,代码段中对Inserted表的查询方式没有带任何条件,似乎这张表只有单行一样,这明显是错误的。
SQL Server为每个触发器创建了两个专业表:INSERTED表和DELETED表。这两个逻辑表,由系统来维护。用户不能对它们进行修改。它们存放在内存中而不是数据库中。这两个表的结构总与被该触发器作用的表的结构相同。触发器执行完成后,与该触发器相关的这两个表也被删除。
- INSERTED表:存放由于执行INSERT或UPDATE语句而要向表中插入的所有行。在执行INSERT或UPDATE操作时,新的行同时添加到激活触发器的表和INSERTED表中,INSERTED表的内容是激活触发器的表中的新行的备份。
- DELETED表:存放由于执行DELETE或UPDATE语句而要从表中删除的所有行。在执行DELETE或UPDATE操作时,被删除的行从激活触发器的表中被移动到DELETED表,这两个表不会有共同的行。
认识到INSERTED表的内容是根据更新条件来的,所以我觉得在使用INSERTED表的时候可以配合游标CURSOR来使用。同时提醒一下,以上代码段中读取INSERTED表的方式,将会返回INSERTED表的最后一行来进行赋值。
SQL Server变量赋值的方式用两种,分别是SET和SELECT,代码段中选择了使用SELECT,而SQL Server推荐使用SET对变量进行赋值。虽然我们在日常工作中使用SELECT的场景比较多,两个赋值方式的概念也了比较解,但他们两者的区别我还是想再强调一下,当赋值失败时,SET和SELECT 的行为是不一样的。这里的赋值失败可能是没有数据或者数据类型不匹配等。此时SELECT会返回上一个值(如果上一个值已经赋值成功),而SET会把NULL赋值给变量。
- 使用SET的情景:1、需要直接赋值,且不需要任何查询,比如变量初始化。2、故意赋予NULL值。3、为了将来的移植而遵循ANSI标准。4、赋予非标量值。
- 使用SELECT的情景:1、直接赋予多值变量。2、通过查询来赋予变量(单值或多值均可)。3、减少代码量。4、为了获取变量如@@ROWCOUNT和@@ERROR的值。