Sql Server 触发器

/*
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


/*
写的比较简单,本人也处于学习阶段,有错误的地方希望可以指点一下。
*/

  

posted @ 2018-11-22 16:34  有意思7  阅读(1682)  评论(0编辑  收藏  举报