/*
单条与多条数据日志的考虑
常规情况下,在编写触发器时,最容易犯的错误就是只考虑到单条数据日志的添加、修改与删除,而没有考虑到多条数据日志的批处理添加、更新与删除的问题。比如:如果你使用INSERT...SELECT命令来批处理添加多条数据日志时,若是触发器没有做周详的判断,很可能会发生不可预料的错误。
下面的范例程序是以SQL SERVER2000的范例数据库pubs中的sales与titles数据表为例来说明,其中,sales数据表是记载书本的每一条销售数据,titles数据表则记载每一本书的基本数据与年度销售额。
我们希望:每当书籍被人订购,发生销售时,不仅会添加书本的销售数据到sales数据表时,还会将书本的销售量(日志于sales数据表的qty字段中)累加到titles数据表的销售总量字段ytd_sales中。
今天,我专门来详细测试这个应用,以期能和大家共同分享!
今后,我还会继续测试和讨论有关触发器的其他应用,构成一个触发器系列的讨论!希望大家继续关注!
*/
--导入数据表sales和titles
select * into sales from pubs.dbo.sales
select * into titles from pubs.dbo.titles
select * from sales
select * from titles
drop table sales
drop table titles
--创建触发器1,该触发器只有在每次添加一条销售数据到sales数据表时能正常运行
create trigger InsertOfSales on Sales
after insert
as
update titles
set ytd_sales=ytd_sales+i.qty
from titles t inner join inserted i on t.title_id=i.title_id
go
--查询添加单条销售数据前,书号PS2106的销售总量为111
select title_id,title,ytd_sales from titles where title_id='ps2106'
--试着添加数据日志
insert sales(stor_id,ord_num,ord_date,qty,payterms,title_id)
values('7896','x0001','06/16/2001',2000,'on invoice','ps2106')
--查询添加单条销售数据后,书号PS2106的销售总量为2111
select title_id,title,ytd_sales from titles where title_id='ps2106'
--暂时删除触发器InsertOfSales
drop trigger InsertOfSales
--创建触发器2,该触发器能够在每次添加一条销售数据或批处理添加多条销售数据到sales数据表时,均能正常运行
create trigger InsertOfSales on Sales
after insert
as
update titles
set ytd_sales=ytd_sales+(select sum(qty) from inserted where title_id=titles.title_id)
where titles.title_id in (select title_id from inserted)
go
--声明一个table变量以便用来存放要批处理添加的多条销售数据
declare @sales table(stor_id char(4) not null,ord_num varchar(20) null,
???ord_date datetime not null,qty smallint not null,
???payterms varchar(12) not null,title_id varchar(6) not null)
--将书号tc7777的销售数据添加到table变量@sales中
insert @sales(stor_id,ord_num,ord_date,qty,payterms,title_id)
values('8042','a0001','06/16/2002',1000,'net 60','tc7777')
insert @sales(stor_id,ord_num,ord_date,qty,payterms,title_id)
values('8042','a0002','06/16/2002',1000,'net 60','tc7777')
insert @sales(stor_id,ord_num,ord_date,qty,payterms,title_id)
values('8042','a0003','06/16/2002',1000,'net 60','tc7777')
--将书号tc4203的销售数据添加到table变量@sales中
insert @sales(stor_id,ord_num,ord_date,qty,payterms,title_id)
values('7067','b0001','06/16/2002',2000,'net 30','tc4203')
insert @sales(stor_id,ord_num,ord_date,qty,payterms,title_id)
values('7067','b0002','06/16/2002',1500,'net 30','tc4203')
--批处理添加销售数据前,书号tc7777与tc4203的销售总量分别为4095与15096
select title_id,title,ytd_sales
from titles
where title_id in ('tc7777','tc4203')
/*
--查询该table变量@sales
select * from @sales
*/
--将table变量@sales中的多条销售数据批处理添加到sale数据表中
insert sales select * from @sales
--再来查询批处理添加销售数据后,书号tc7777与tc4203的销售总量
select title_id,title,ytd_sales from titles where title_id in ('tc7777','tc4203')
--暂时删除触发器InsertOfSales
drop trigger InsertOfSales
--触发器2的缺点:如果仅仅是添加一条销售数据也要利用批处理添加多条的程序代码来完成,效率将会很低,智能性低
--下面创建的触发器3,将更智能化点:能够判断用户是添加一条数据还是批处理添加多条数据,然后使用不同的程序代码来处理
--创建触发器3,该触发器通过无参数@@rowcount可以判断用户是添加一条还是批处理添加多条数据
create trigger InsertOfSales on Sales
after insert
as
if @@rowcount=1
begin
?update titles
?set ytd_sales=ytd_sales+i.qty
?from titles t inner join inserted i on t.title_id=i.title_id
end
else
begin
?update titles
?set ytd_sales=ytd_sales+(select sum(qty) from inserted where title_id=titles.title_id)
?where titles.title_id in (select title_id from inserted)
end
go
--声明一个table变量以便用来存放要批处理添加的多条销售数据
declare @sales table(stor_id char(4) not null,ord_num varchar(20) null,
???ord_date datetime not null,qty smallint not null,
???payterms varchar(12) not null,title_id varchar(6) not null)
--将书号tc7777的销售数据添加到table变量@sales中
insert @sales(stor_id,ord_num,ord_date,qty,payterms,title_id)
values('8042','a0001','06/16/2002',1000,'net 60','tc7777')
insert @sales(stor_id,ord_num,ord_date,qty,payterms,title_id)
values('8042','a0002','06/16/2002',1000,'net 60','tc7777')
insert @sales(stor_id,ord_num,ord_date,qty,payterms,title_id)
values('8042','a0003','06/16/2002',1000,'net 60','tc7777')
--将书号tc4203的销售数据添加到table变量@sales中
insert @sales(stor_id,ord_num,ord_date,qty,payterms,title_id)
values('7067','b0001','06/16/2002',2000,'net 30','tc4203')
insert @sales(stor_id,ord_num,ord_date,qty,payterms,title_id)
values('7067','b0002','06/16/2002',1500,'net 30','tc4203')
--批处理添加销售数据前,书号ps2106、tc7777与tc4203的销售总量分别为4095与15096
select title_id,title,ytd_sales
from titles
where title_id in ('ps2106','tc7777','tc4203')
--试着添加单条数据日志
insert sales(stor_id,ord_num,ord_date,qty,payterms,title_id)
values('7896','x0001','06/16/2001',2000,'on invoice','ps2106')
--将table变量@sales中的多条销售数据批处理添加到sale数据表中
insert sales select * from @sales
--再来查询批处理添加销售数据后,书号ps2106、tc7777与tc4203的销售总量
select title_id,title,ytd_sales from titles where title_id in ('ps2106','tc7777','tc4203')?