/*
SQL Server触发器
1.什么是触发器
触发器是一种特殊类型的存储过程,因为它和存储过程有一样的特征,都是预用写好的Sql命令存储在SqlServer服务器中。
触发器在指定的表中的数据发生变化(insert/update/delete)的时候会自动执行。它与存储过程的区别也在此,因为存储过程是需要我们用命令去调用的。
触发器一般用在比check约束更加复杂的约束上面。
注意:触发器本身就是一个事务,所以在触发器里面可以对修改数据进行一些特殊的检查。如果不满足可以利用事务回滚,撤销操作。
2.触发器分类
DML触发器和DDL触发器。
DML触发器:
当数据库中表中的数据发生变化时,包括insert,update,delete任意操作,如果我们对该表写了对应的DML触发器,那么该触发器将自动执行。
DML触发器的主要作用在于强制执行业 务规则,以及扩展Sql Server约束,默认值等。因为我们知道约束只能约束同一个表中的数据,而触发器中则可以执行任意Sql命令。
例子:我们想要在送货后减少库存的数量,那我们就可以在送货单的表上写update触发器,用来减少库存的数量。
DDL触发器:
它是Sql Server2005新增的触发器,主要用于审核与规范对数据库中表,触发器,视图等结构上的操作。比如在修改表,修改列,新增表,新增列等。
它在数据库结构发生变化时执行,我们主要用它来记录数据库的修改过程,以及限制程序员对数据库的修改,比如不允许删除某些指定表等。
DML触发器:
1.after触发器(之后触发)
a.insert触发器
b.update触发器
c.delete触发器
2.insert of 触发器 之前触发
after触发器只有在执行insert、update、delete之后才能触发,且只能定义在表上。
而insert of 触发器表示并不执行其定义的操作(insert、update、delete)而仅是执行触发器本身。既可以在表上定义,也可在视图上定义。
3.触发器有两个非常特殊,非常重要的两个表。
insetred:插入表
deleted:删除表
这两个是逻辑表,也是虚表。由系统在内存中自动创建这两张表,这两张表不会存储在数据库中,而且这两张表都是只读的。这两张表的结果总是与被
触发器应用的表的结构相同。当触发器完成后,这两表将会被删除。
Inserted表的数据是插入或是修改后的数据,而deleted表的数据是更新前的或是删除的数据。
4.编码实现
业务逻辑:有水果销售表和水果库存表,
*/
--创建表
create table FruitsSaleTable
(
FruitsName varchar(20) primary key not null, --水果名称
Supplier varchar(50), --供货商
SaleNumber int, --销售数量
SaleUnitPrice money, --单价
SaleTotalSum money --销售总金额
)
insert into FruitsSaleTable(FruitsName,Supplier,SaleNumber,SaleUnitPrice,SaleTotalSum)
values('冰糖雪梨','B',20,10,200)
create table FruitsStock
(
FruitsName varchar(20) primary key not null, --水果名称
StockNumber int, --库存数量
StockUnitPrice money, --库存单价
StockTotalSum money --库存总金额
)
/*
Insert:
首先我们在库存表(FruitsStock)中创建一个Insert触发器,
目的:1.库存总金额=库存数量*库存单价 这个等式成立
2.确保收货时 “库存数量”>0 不然收货动作将毫无意义
*/
create trigger I_insert_FruitsStock --创建触发器
on FruitsStock --作用那张表
for insert --触发条件
as
--提交事务
begin transaction
--判断收货库存是否>0
if not exists
(
select StockNumber from FruitsStock where FruitsName in (select FruitsName from inserted) and StockNumber >0
)
begin
--不满足条件,提示
raiserror('错误,收货数量不能小于0',16,1)
--事务回滚
rollback
return
end
--条件满足,强制执行SQL,保证业务逻辑
update FruitsStock set StockTotalSum = StockNumber * StockUnitPrice
where FruitsName in (select FruitsName from inserted)
--提交事务
commit transaction
go
--测试触发器
--1.数据都正确
insert into FruitsStock
(FruitsName,StockNumber,StockUnitPrice,StockTotalSum)
values('苹果',50,10,500)
/*
结果:OK
(1 行受影响)
*/
--2.库存总金额<>库存数量*库存单件
insert into FruitsStock
(FruitsName,StockNumber,StockUnitPrice,StockTotalSum)
values('冰糖雪梨',30,10,100)
/*
结果:OK
(1 行受影响)
查询结果可的:触发器自动进行计算,结果中显示正确的库存总金额
*/
--3.当收货数量为<=0时
insert into FruitsStock
(FruitsName,StockNumber,StockUnitPrice,StockTotalSum)
values('蓝莓',0,10,100)
/*
结果:OK
消息 50000,级别 16,状态 1,过程 I_insert_FruitsStock,第 138 行
错误,收货数量不能小于0
消息 3609,级别 16,状态 1,第 124 行
事务在触发器中结束。批处理已中止。
*/
/*
update:
首先我们在销售表(FruitsSaleTable)中创建一个update触发器,
业务逻辑:更改销售价格,销售总金额一起改变
*/
create trigger U_update_FruitsSaleTable
on FruitsSaleTable
for update
as
if update(SaleUnitPrice)
declare @price money --更改后的销售价格
--提交事务
begin transaction
select @price=SaleUnitPrice from FruitsSaleTable where FruitsName in (select FruitsName from inserted)
--begin
--if(@price<=0)
-- print'价格修改错误'
-- rollback
-- return
-- end
update FruitsSaleTable set SaleTotalSum =SaleNumber * @price where FruitsName in (select FruitsName from inserted)
commit transaction
go
/*
update触发器测试
*/
update FruitsSaleTable set SaleUnitPrice=7 where FruitsName='苹果'
/*
结果:
(1 行受影响)
*/
/*
delete触发器:
业务逻辑:删除库存表中数据时同时删除销售表
*/
create trigger D_delete_FruitsStock
on FruitsStock
for delete
as
begin
delete FruitsStock from FruitsStock fs,deleted d where fs.FruitsName=d.FruitsName
delete FruitsSaleTable from FruitsSaleTable st,deleted d where st.FruitsName=d.FruitsName
end
go
/*
delete触发器
(0 行受影响)
(1 行受影响)
*/
delete from FruitsStock where FruitsName='冰糖雪梨'
select * from FruitsStock
select * from FruitsSaleTable
/*
写的比较简单,本人也处于学习阶段,有错误的地方希望可以指点一下。
*/