触发器

  1 ExpandedBlockStart.gif ContractedBlock.gif /**/ /*
  2InBlock.gif建立虚拟测试环境,包含:表[卷烟库存表],表[卷烟销售表]。
  3InBlock.gif请大家注意跟踪这两个表的数据,体会触发器到底执行了什么业务逻辑,对数据有什么影响。
  4InBlock.gif为了能更清晰的表述触发器的作用,表结构存在数据冗余,且不符合第三范式,这里特此说明。
  5ExpandedBlockEnd.gif*/
 
  6 None.gif USE  test
  7 None.gif GO
  8 None.gif
  9 None.gif IF   EXISTS  ( SELECT  NAME  FROM  SYSOBJECTS  WHERE  XTYPE  =   ' U '   AND  NAME  =   ' 卷烟库存表 ' )
 10 None.gif DROP   TABLE  卷烟库存表
 11 None.gif GO
 12 None.gif IF   EXISTS  ( SELECT  NAME  FROM  SYSOBJECTS  WHERE  XTYPE  =   ' U '   AND  NAME  =   ' 卷烟销售表 ' )
 13 None.gif DROP   TABLE  卷烟销售表
 14 None.gif GO
 15 None.gif
 16 None.gif -- 业务规则:销售金额 = 销售数量 * 销售单价 业务规则。
 17 None.gif
 18 None.gif CREATE   TABLE  卷烟销售表
 19 None.gif(
 20 None.gif卷烟品牌  VARCHAR ( 40 PRIMARY   KEY   NOT   NULL ,
 21 None.gif购货商  VARCHAR ( 40 NULL ,
 22 None.gif销售数量  INT   NULL ,
 23 None.gif销售单价  MONEY   NULL ,
 24 None.gif销售金额  MONEY   NULL
 25 None.gif)
 26 None.gif GO
 27 None.gif
 28 None.gif -- 业务规则:库存金额 = 库存数量 * 库存单价 业务规则。
 29 None.gif
 30 None.gif CREATE   TABLE  卷烟库存表
 31 None.gif(
 32 None.gif卷烟品牌  VARCHAR ( 40 PRIMARY   KEY   NOT   NULL ,
 33 None.gif库存数量  INT   NULL ,
 34 None.gif库存单价  MONEY   NULL ,
 35 None.gif库存金额  MONEY   NULL
 36 None.gif)
 37 None.gif GO
 38 None.gif
 39 None.gif -- 创建触发器,示例1
 40 None.gif
 41 ExpandedBlockStart.gifContractedBlock.gif /**/ /*
 42InBlock.gif创建触发器[T_INSERT_卷烟库存表],这个触发器较简单。
 43InBlock.gif说明: 每当[卷烟库存表]发生 INSERT 动作,则引发该触发器。
 44InBlock.gif触发器功能: 强制执行业务规则,保证插入的数据中,库存金额 = 库存数量 * 库存单价。
 45InBlock.gif注意: [INSERTED]、[DELETED]为系统表,不可创建、修改、删除,但可以调用。
 46InBlock.gif重要: 这两个系统表的结构同插入数据的表的结构。
 47ExpandedBlockEnd.gif*/

 48 None.gif IF   EXISTS  ( SELECT  NAME  FROM  SYSOBJECTS  WHERE  XTYPE  =   ' TR '   AND  NAME  =   ' T_INSERT_卷烟库存表 ' )
 49 None.gif DROP   TRIGGER  T_INSERT_卷烟库存表
 50 None.gif GO
 51 None.gif
 52 None.gif CREATE   TRIGGER  T_INSERT_卷烟库存表
 53 None.gif ON  卷烟库存表
 54 None.gif FOR   INSERT
 55 None.gif AS
 56 None.gif -- 提交事务处理
 57 None.gif BEGIN   TRANSACTION
 58 None.gif -- 强制执行下列语句,保证业务规则
 59 None.gif UPDATE  卷烟库存表
 60 None.gif SET  库存金额  =  库存数量  *  库存单价
 61 None.gif WHERE  卷烟品牌  IN  ( SELECT  卷烟品牌  from  INSERTED)
 62 None.gif COMMIT   TRANSACTION
 63 None.gif GO
 64 None.gif
 65 ExpandedBlockStart.gifContractedBlock.gif /**/ /* 
 66InBlock.gif针对[卷烟库存表],插入测试数据:
 67InBlock.gif注意,第一条数据(红塔山新势力)中的数据符合业务规则,
 68InBlock.gif第二条数据(红塔山人为峰)中,[库存金额]空,不符合业务规则,
 69InBlock.gif第三条数据(云南映像)中,[库存金额]不等于[库存数量]乘以[库存单价],不符合业务规则。
 70InBlock.gif第四条数据库存数量为0。
 71InBlock.gif请注意在插入数据后,检查[卷烟库存表]中的数据是否 库存金额 = 库存数量 * 库存单价。
 72ExpandedBlockEnd.gif*/

 73 None.gif
 74 None.gif INSERT   INTO  卷烟库存表(卷烟品牌,库存数量,库存单价,库存金额)
 75 None.gif SELECT   ' 红塔山新势力 ' , 100 , 12 , 1200   UNION   ALL
 76 None.gif SELECT   ' 红塔山人为峰 ' , 100 , 22 , NULL   UNION   ALL
 77 None.gif SELECT   ' 云南映像 ' , 100 , 60 , 500   UNION   ALL
 78 None.gif SELECT   ' 玉溪 ' , 0 , 30 , 0
 79 None.gif GO
 80 None.gif
 81 None.gif -- 查询数据
 82 None.gif
 83 None.gif SELECT   *   FROM  卷烟库存表
 84 None.gif GO
 85 ExpandedBlockStart.gifContractedBlock.gif /**/ /*
 86InBlock.gif
 87InBlock.gif结果集
 88InBlock.gif
 89InBlock.gifRecordId 卷烟品牌 库存数量 库存单价 库存金额
 90InBlock.gif-------- ------------ -------- ------- ---------
 91InBlock.gif1 红塔山新势力 100 12.0000 1200.0000
 92InBlock.gif2 红塔山人为峰 100 22.0000 2200.0000
 93InBlock.gif3 云南映像 100 60.0000 6000.0000
 94InBlock.gif4 玉溪 0 30.0000 .0000
 95InBlock.gif
 96InBlock.gif(所影响的行数为 4 行)
 97InBlock.gif
 98ExpandedBlockEnd.gif*/

 99 None.gif
100 None.gif -- 触发器示例2
101 None.gif
102 ExpandedBlockStart.gifContractedBlock.gif /**/ /*
103InBlock.gif创建触发器[T_INSERT_卷烟销售表],该触发器较复杂。
104InBlock.gif说明: 每当[卷烟库存表]发生 INSERT 动作,则引发该触发器。
105InBlock.gif触发器功能: 实现业务规则。
106InBlock.gif业务规则: 如果销售的卷烟品牌不存在库存或者库存为零,则返回错误。
107InBlock.gif否则则自动减少[卷烟库存表]中对应品牌卷烟的库存数量和库存金额。
108ExpandedBlockEnd.gif*/

109 None.gif IF   EXISTS  ( SELECT  NAME  FROM  SYSOBJECTS  WHERE  XTYPE  =   ' TR '   AND  NAME  =   ' T_INSERT_卷烟销售表 ' )
110 None.gif DROP   TRIGGER  T_INSERT_卷烟销售表
111 None.gif GO
112 None.gif
113 None.gif CREATE   TRIGGER  T_INSERT_卷烟销售表
114 None.gif ON  卷烟销售表
115 None.gif FOR   INSERT
116 None.gif AS
117 None.gif BEGIN   TRANSACTION
118 None.gif -- 检查数据的合法性:销售的卷烟是否有库存,或者库存是否大于零
119 None.gif IF   NOT   EXISTS  (
120 None.gif SELECT  库存数量
121 None.gif FROM  卷烟库存表
122 None.gif WHERE  卷烟品牌  IN  ( SELECT  卷烟品牌  FROM  INSERTED)
123 None.gif)
124 None.gif BEGIN
125 None.gif -- 返回错误提示
126 None.gif RAISERROR ( ' 错误!该卷烟不存在库存,不能销售。 ' , 16 , 1 )
127 None.gif -- 回滚事务
128 None.gif ROLLBACK
129 None.gif RETURN
130 None.gif END
131 None.gif
132 None.gif IF   EXISTS  (
133 None.gif SELECT  库存数量
134 None.gif FROM  卷烟库存表
135 None.gif WHERE  卷烟品牌  IN  ( SELECT  卷烟品牌  FROM  INSERTED)  AND
136 None.gif库存数量  <=   0  
137 None.gif)
138 None.gif BEGIN
139 None.gif -- 返回错误提示
140 None.gif RAISERROR ( ' 错误!该卷烟库存小于等于0,不能销售。 ' , 16 , 1 )
141 None.gif -- 回滚事务
142 None.gif ROLLBACK
143 None.gif RETURN
144 None.gif END
145 None.gif
146 None.gif -- 对合法的数据进行处理
147 None.gif
148 None.gif -- 强制执行下列语句,保证业务规则
149 None.gif UPDATE  卷烟销售表
150 None.gif SET  销售金额  =  销售数量  *  销售单价
151 None.gif WHERE  卷烟品牌  IN  ( SELECT  卷烟品牌  FROM  INSERTED)
152 None.gif
153 None.gif DECLARE   @卷烟品牌   VARCHAR ( 40 )
154 None.gif SET   @卷烟品牌   =  ( SELECT  卷烟品牌  FROM  INSERTED)
155 None.gif
156 None.gif DECLARE   @销售数量   MONEY
157 None.gif SET   @销售数量   =  ( SELECT  销售数量  FROM  INSERTED)
158 None.gif
159 None.gif UPDATE  卷烟库存表
160 None.gif SET  库存数量  =  库存数量  -   @销售数量 ,
161 None.gif库存金额  =  (库存数量  -   @销售数量 ) * 库存单价
162 None.gif WHERE  卷烟品牌  =   @卷烟品牌
163 None.gif COMMIT   TRANSACTION
164 None.gif GO
165 None.gif
166 None.gif -- 请大家自行跟踪[卷烟库存表]和[卷烟销售表]的数据变化。
167 None.gif-- 针对[卷烟销售表],插入第一条测试数据,该数据是正常的。
168 None.gif
169 None.gif INSERT   INTO  卷烟销售表(卷烟品牌,购货商,销售数量,销售单价,销售金额)
170 None.gif SELECT   ' 红塔山新势力 ' , ' 某购货商 ' , 10 , 12 , 1200
171 None.gif GO
172 None.gif
173 None.gif -- 针对[卷烟销售表],插入第二条测试数据,该数据 销售金额 不等于 销售单价 * 销售数量。
174 None.gif-- 触发器将自动更正数据,使 销售金额 等于 销售单价 * 销售数量。
175 None.gif
176 None.gif INSERT   INTO  卷烟销售表(卷烟品牌,购货商,销售数量,销售单价,销售金额)
177 None.gif SELECT   ' 红塔山人为峰 ' , ' 某购货商 ' , 10 , 22 , 2000
178 None.gif GO
179 None.gif
180 None.gif -- 针对[卷烟销售表],插入第三条测试数据,该数据中的卷烟品牌在 卷烟库存表中找不到对应。
181 None.gif-- 触发器将报错。
182 None.gif
183 None.gif INSERT   INTO  卷烟销售表(卷烟品牌,购货商,销售数量,销售单价,销售金额)
184 None.gif SELECT   ' 红河V8 ' , ' 某购货商 ' , 10 , 60 , 600
185 None.gif GO
186 None.gif
187 ExpandedBlockStart.gifContractedBlock.gif /**/ /*
188InBlock.gif结果集
189InBlock.gif服务器: 消息 50000,级别 16,状态 1,过程 T_INSERT_卷烟销售表,行 15
190InBlock.gif错误!该卷烟不存在库存,不能销售。
191ExpandedBlockEnd.gif*/

192 None.gif
193 None.gif -- 针对[卷烟销售表],插入第三条测试数据,该数据中的卷烟品牌在 卷烟库存表中库存为0。
194 None.gif-- 触发器将报错。
195 None.gif
196 None.gif INSERT   INTO  卷烟销售表(卷烟品牌,购货商,销售数量,销售单价,销售金额)
197 None.gif SELECT   ' 玉溪 ' , ' 某购货商 ' , 10 , 30 , 300
198 None.gif GO
199 None.gif
200 ExpandedBlockStart.gifContractedBlock.gif /**/ /*
201InBlock.gif结果集
202InBlock.gif服务器: 消息 50000,级别 16,状态 1,过程 T_INSERT_卷烟销售表,行 29
203InBlock.gif错误!该卷烟库存小于等于0,不能销售。
204ExpandedBlockEnd.gif*/

205 None.gif -- 查询数据
206 None.gif SELECT   *   FROM  卷烟库存表
207 None.gif
208 None.gif SELECT   *   FROM  卷烟销售表
209 None.gif GO
210 None.gif
211 ExpandedBlockStart.gifContractedBlock.gif /**/ /*
212InBlock.gif补充:
213InBlock.gif1、本示例主要通过一个简单的业务规则实现来进行触发器使用的说明,具体的要根据需要灵活处理;
214InBlock.gif2、关于触发器要理解并运用好 INSERTED ,DELETED 两个系统表;
215InBlock.gif3、本示例创建的触发器都是 FOR INSERT ,具体的语法可参考:
216InBlock.gif
217InBlock.gifTrigger语法
218InBlock.gif
219InBlock.gifCREATE TRIGGER trigger_name 
220InBlock.gifON { table | view } 
221InBlock.gif[ WITH ENCRYPTION ] --用于加密触发器
222InBlock.gif{
223InBlock.gif{ { FOR | AFTER | INSTEAD OF } { [ INSERT ] [ , ] [ UPDATE ] }
224InBlock.gif[ WITH APPEND ]
225InBlock.gif[ NOT FOR REPLICATION ]
226InBlock.gifAS
227InBlock.gif[ { IF UPDATE ( column )
228InBlock.gif[ { AND | OR } UPDATE ( column ) ]
229InBlock.gifdot.gifn ]
230InBlock.gif| IF ( COLUMNS_UPDATED ( ) { bitwise_operator } updated_bitmask )
231InBlock.gif{ comparison_operator } column_bitmask [ dot.gifn ]
232InBlock.gif} ] 
233InBlock.gifsql_statement [ dot.gifn ] 
234InBlock.gif
235InBlock.gif
236InBlock.gif
237InBlock.gif4、关于触发器,还应该注意
238InBlock.gif(1)、DELETE 触发器不能捕获 TRUNCATE TABLE 语句。
239InBlock.gif(2)、触发器中不允许以下 Transact-SQL 语句:
240InBlock.gifALTER DATABASE CREATE DATABASE DISK INIT 
241InBlock.gifDISK RESIZE DROP DATABASE LOAD DATABASE 
242InBlock.gifLOAD LOG RECONFIGURE RESTORE DATABASE 
243InBlock.gifRESTORE LOG 
244InBlock.gif(3)、触发器最多可以嵌套 32 层。
245InBlock.gif
246ExpandedBlockEnd.gif*/

247 None.gif
248 None.gif -- 修改触发器
249 None.gif-- 实质上,是将 CREATE TRIGGER dot.gif 修改为 ALTER TRIGGER dot.gif即可。
250 None.gif
251 None.gif -- 删除触发器
252 None.gif DROP   TRIGGER  xxx
253 None.gif GO
254 None.gif
255 None.gif -- 删除测试环境
256 None.gif DROP   TABLE  卷烟库存表
257 None.gif GO
258 None.gif DROP   TABLE  卷烟销售表
259 None.gif GO
260 None.gif DROP   TRIGGER  T_INSERT_卷烟库存表
261 None.gif GO
262 None.gif DROP   TRIGGER  T_INSERT_卷烟销售表
263 None.gif GO
264 ExpandedBlockStart.gifContractedBlock.gif /**/ /**----------------------------------------------------------------------
265InBlock.gif##################################################################
266InBlock.gif触发器的基础知识和例子
267InBlock.gif:create trigger tr_name
268InBlock.gifon table/view
269InBlock.gif{for | after | instead of } [update][,][insert][,][delete]
270InBlock.gif[with encryption]
271InBlock.gifas {batch | if update (col_name) [{and|or} update (col_name)] }
272InBlock.gif
273InBlock.gif说明:
274InBlock.gif1 tr_name :触发器名称
275InBlock.gif2 on table/view :触发器所作用的表。一个触发器只能作用于一个表
276InBlock.gif3 for 和after :同义
277InBlock.gif4 after 与instead of :sql 2000新增项目afrer 与 instead of 的区别
278InBlock.gifAfter 
279InBlock.gif在触发事件发生以后才被激活,只可以建立在表上 
280InBlock.gifInstead of
281InBlock.gif代替了相应的触发事件而被执行,既可以建立在表上也可以建立在视图上
282InBlock.gif5 insert、update、delete:激活触发器的三种操作,可以同时执行,也可选其一
283InBlock.gif6 if update (col_name):表明所作的操作对指定列是否有影响,有影响,则激活触发器。此外,因为delete 操作只对行有影响,
284InBlock.gif所以如果使用delete操作就不能用这条语句了(虽然使用也不出错,但是不能激活触发器,没意义)。
285InBlock.gif7 触发器执行时用到的两个特殊表:deleted ,inserted
286InBlock.gifdeleted 和inserted 可以说是一种特殊的临时表,是在进行激活触发器时由系统自动生成的,其结构与触发器作用的表结构是一
287InBlock.gif样的,只是存放 的数据有差异。
288InBlock.gif
289InBlock.gif
290InBlock.gif下面表格说明deleted 与inserted 数据的差异
291InBlock.gifdeleted 与inserted 数据的差异
292InBlock.gifInserted 
293InBlock.gif存放进行insert和update 操作后的数据 
294InBlock.gifDeleted
295InBlock.gif存放进行delete 和update操作前的数据
296InBlock.gif注意:update 操作相当于先进行delete 再进行insert ,所以在进行update操作时,修改前的数据拷贝一条到deleted 表中,修改后
297InBlock.gif的数据在存到触发器作用的表的同时,也同时生成一条拷贝到insered表中 
298ExpandedBlockEnd.gif---------------------------------------------------------------------------*/

转载于:https://www.cnblogs.com/ssihc/archive/2006/07/31/464249.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值