- 注册时间
- 2007-4-18
- 荣誉
- 0 点
- 金币
- 1411 个
- 阅读权限
- 200
- 积分
- 123
- 帖子
- 181
- 精华
- 1
- UID
- 4032
 
- 荣誉
- 0 点
- 金币
- 1411 个
- 注册时间
- 2007-4-18
- 阅读权限
- 200
- 精华
- 1
- 积分
- 123
- 帖子
- 181
|
发表于 2007-11-3 14:05:29
|显示全部楼层
刚刚看到有人说触发器不是太明白,我在这里就班门弄斧的稍微谈谈自己的看法:% y+ B# @+ c$ t( [, s
先引用一段 关于触发器的说明(最好慢慢看完,如果这个说明你都不原意拜读,那我就没办法了),
* q g: q9 `5 w! i- |% n9 r在针对易飞ERP中的触发器做几个举例说明。! _! ~: k# X/ ^ ~" f( [$ A
=============================================================================
( e) C: `1 Y8 Z/ w触发器是一种特殊的存储过程,类似于其它编程语言中的事件函数,SQL Server? 允许为 INSERT、UPDATE、DELETE 创建触发器,当在表(视图)中插入、更新、删除记录时,触发一个或一系列 T-SQL 语句。 (定义)( M j. c/ T# @* E
4 Z) Y1 }+ I0 c5 eFOR CREATE TRIGGER 语句
& c' s" {$ e& M! sFOR 关键字之后可以跟 INSERT、UPDATE、DELETE 中的一个或多个,也就是说在其它情况下是不会触发触发器的, 包括 SELECT、TRUNCATE、WRITETEXT、UPDATETEXT。
; d2 N" `- Z+ C
: I0 M& o8 @( ~; X# wTRUNCATE TABLE 和不带 WHERE 的 DELETE 功能是一样的,都是删除表中的所有数据,不过 TRUNCATE TABLE 速度更快,占用的日志更少,这是因为 TRUNCATE TABLE 直接释放数据页并且在事务日志中也只记录数据页的释放,而 DELETE 是一行一行地删除,在事务日志中要记录每一条记录的删除。
/ s; u. ]- l1 P2 a ?# x! D! s3 g# f9 y$ W
那么可不可以用 TRUNCATE TABLE 代替不带 WHERE 的 DELETE 呢?在以下情况是不行的:
( R8 a( p& j9 Q0 E: A! t$ t1、要保留标识的情况下不能用 TRUNCATE TABLE,因为 TRUNCATE TABLE 会重置标识。 8 Q1 w! G, J+ x! L; Z1 ]2 L* o+ W
2、需要使用触发器的情况下不能使用 TRUNCATE TABLE ,它不会激发触发器。
5 {2 v5 A, C, C6 G" v, q8 u0 K3、对于由 FOREIGN KEY 约束引用的表(即主键所在的表,不是外键所在的表)不能使用 TRUNCATE TABLE。 6 w$ m$ Y& w7 x/ _
4、对于参与了索引视图的表不能使用 TRUNCATE TABLE ,注意指索引视图,并非普通视图。
; k2 k0 o {8 r5 l; h+ t
+ y ~; h) k5 {* {" Z不能在触发器中使用的语句
9 Q+ [, Z3 e8 Y' V0 j. t. @' E) o4 R, [. I+ S9 D/ S5 Z$ x$ M
触发器中可以使用大多数 T-SQL 语句,但如下一些语句是不能在触发器中使用的。
, A3 `5 n" `2 N6 U6 h3 \CREATE 语句,如:CREATE DATABASE、CREATE TABLE、CREATE INDEX 等。 3 c/ Z4 |" P& @2 q
ALTER 语句,如:ALTER DATABASE、ALTER TABLE、ALTER INDEX 等。
% L }: s' A+ w3 ADROP 语句,如:DROP DATABASE、DROP TABLE、DROP INDEX 等。
$ R f5 p: o; H$ O( k1 G% h, ]DISK 语句,如:DISK INIT、DISK RESIZE。
: y0 m6 E" G& m. @7 B! hLOAD 语句,如:LOAD DATABASE、LOAD LOG。 * R% q1 ^) ]5 @) Z
RESTORE 语句,如:RESTORE DATABASE、RESTORE LOG。 3 |2 u5 y/ E N1 _( U: ~
RECONFIGURE : K4 c( w3 p0 Y& z# ]( k5 Q! X5 D
说明:有人说不能用 TRUNCATE TABLE 语句,其实是可以的。 & n' F V8 K% R4 L
1 g6 P( {0 N7 l# D! i ]5 t, _# g8 p& L% u9 s7 V# V
% C2 G; g2 w1 Q0 [+ v查看某个触发器的内容 1 f% q/ q, Q) U
0 k* O& \# M! g, \use 数据库名
) i8 u$ S' U! ogo 3 ^. u7 @3 ~6 L' d/ Z
exec sp_helptext '触发器名称'
" w% S; b' u: v" ?" D将会以表的样式显示触发器内容。
5 ?, Z& Q; {" A" D, j. [ d除了触发器外,sp_helptext 还可以显示 规则、默认值、未加密的存储过程、用户定义函数、视图的文本 8 Z; ?' M6 H% F7 `, Q
用企业管理器查看
( s) N9 F# P7 m! @" Z$ ?( z; W8 W) G5 P0 s
或者在表上点右键->“所有任务”->“管理触发器”,选择所要查看的触发器 9 H1 ~$ U: @6 |) o& E
' O" n0 x; @7 |5 _0 q
查看当前数据库中有哪些触发器
% n% C( A i4 W! Z2 @7 y1 Y2 h0 Y+ L( M
在查询分析器中运行: , C( l- l- W0 |" g8 a, P7 V
\* }8 P7 T. R6 u3 i( vuse 数据库名 % m4 @, U* b% n0 j& E
go ' |% `0 _0 |2 L, o8 P
select * from sysobjects where xtype='TR'
& p# ~+ k) ^" H* n- c) q0 lsysobjects 保存着数据库的对象,其中 xtype 为 TR 的记录即为触发器对象。在 name 一列,我们可以看到触发器名称。 * I: e) [: w) h
6 a, b$ I6 c: M) w3 E2 {
删除触发器
7 J' a- k" u, _% z8 Y2 A: m4 @2 u2 e2 t( w
$ Y# g" h& S- C) F
用查询分析器删除
6 e3 H" M3 h2 x; X% M; r% s- V7 B在查询分析器中使用 drop trigger 触发器名称 来删除触发器。 : r3 V! P5 T0 `1 Q9 u
也可以同时删除多个触发器:drop trigger 触发器名称,触发器名称...
4 l4 Y; y9 S6 ~5 ]注意:触发器名称是不加引号的。在删除触发器之前可以先看一下触发器是否存在: 0 j0 t/ U$ |0 b6 _3 v: T9 o
if Exists(select name from sysobjects where name=触发器名称 and xtype='TR')
% w L0 @8 a9 g& n% _$ L( F7 P3 ]2 |
用企业管理器删除
: j/ y! o1 W9 o# e: u3 T在企业管理器中,在表上点右键->“所有任务”->“管理触发器”,选中所要删除的触发器,然后点击“删除”。
# g4 a. v2 o" l w
0 V1 w9 D3 ]: n" m
5 K2 w4 Y' }% u2 G- z重命名触发器
0 z. C$ y* G; H& u用查询分析器重命名
1 c% }- p2 b* Y/ ^' m' bexec sp_rename 原名称, 新名称 ! S |' {% F4 s% r8 [
sp_rename 是 SQL Server? 自带的一个存储过程,用于更改当前数据库中用户创建的对象的名称,如表名、列表、索引名等。
' {5 l. h5 S2 ^9 k
& [( ^! ~8 F4 {. j用企业管理器重命名 3 j/ V7 S, \1 m- [& x) a* L" C3 ~
在表上点右键->“所有任务”->“管理触发器”,选中所要重命名的触发器,修改触发器语句中的触发器名称,点击“确定”。 / ^1 A: l9 p0 R5 }& k. G
$ g. t/ @# W2 y% T, G) {
查看触发器的属性
: ^( ^5 N+ u* s. V& \( C; c* _7 n% G
存储过程 sp_helptrigger 用于查看触发器的属性。
+ O% ]4 v L/ ~+ U; W1 B+ O" `7 z
/ o4 s7 t0 W7 x2 |8 U' w& H" J2 Ysp_helptrigger 有两个参数:第一个参数为表名;第二个为触发器类型,为 char(6) 类型,可以是 INSERT、UPDATE、DELETE,如果省略则显示指定表中所有类型触发器的属性。
; |6 R# A ~0 u6 K2 T
# `* I& ?9 n, i! u6 i* W例:
7 a# \$ M( Q' S) }% Q# V, ^8 M2 o# s0 u. W7 I
use 数据库名 ( w4 m- w- q$ S0 v9 s
go 1 Y+ U# s' U' _/ n: T, T8 ?8 `
exec sp_helptrigger tbl # q2 J! E, X8 l! D9 B# t
' E. H$ f3 c; Y4 o0 `, o A8 _. A
触发器更多语法
) C3 V9 p% f+ R, L$ V" M4 @6 J- h! |& Y1 ?' Q- j1 f5 }
INSTEAD OF
9 Y H- B" b& [+ o/ l执行触发器语句,但不执行触发触发器的 SQL 语句,比如试图删除一条记录时,将执行触发器指定的语句,此时不再执行 delete 语句。例:
% \9 V# l% {8 M/ \. F7 U/ G- Qcreate trigger f ! o" T3 n, P+ z* H4 v( {- p" d3 f6 }& u
on tbl
: N$ I: w8 d% g8 Y; i- R2 q; o5 |: W* N4 yinstead of delete - j9 Y+ A6 `5 b3 O T# t- g
as
: D! c8 \( c( Y! O3 N `) o) [+ Qinsert into Logs... % n! i! }/ ~, g9 k
2 ? W7 U, C: i+ E: y: @! FIF UPDATE(列名)
( J2 d. T3 ^3 s# a! L; j7 C检查是否更新了某一列,用于 insert 或 update,不能用于 delete。例: 0 i: M0 T- i p+ R) f) Y8 X
create trigger f 8 l4 k( X& e# Y4 Y3 g
on tbl
: y' E& }/ S2 J3 Tfor update ; C, R" d3 Q( k+ X$ I' H
as + a1 Y7 @7 S" P5 h0 I" u
if update(status) or update(title) 8 ~. t( V4 J2 n, U9 d# i7 g0 `: \2 r+ q
sql_statement --更新了 status 或 title 列
5 R: Y! ~- K$ N5 Y: W- W0 Y+ R& U0 R" f
inserted、deleted
, F; k2 B9 z+ q0 Q$ ?, e) L0 u这是两个虚拟表,inserted 保存的是 insert 或 update 之后所影响的记录形成的表,deleted 保存的是 delete 或 update 之前所影响的记录形成的表。例:
) l4 a% W; R* Ccreate trigger tbl_delete
; e/ T: r0 C3 v: u5 j0 v$ ?on tbl
* W3 C; S6 L" ~for delete
; f7 G+ K- A% [3 t& \as 5 ]) k5 x4 y# h$ L: h3 S
declare @title varchar(200)
1 b0 }& X/ r8 D* Tselect @title=title from deleted ; |0 p) \2 N# `8 E1 v' {& H+ y/ ^/ E
insert into Logs(logContent) values('删除了 title 为:' + title + '的记录')
# ? B' |) d; `- U2 U说明:如果向 inserted 或 deleted 虚拟表中取字段类型为 text、image 的字段值时,所取得的值将会是 null。
* D( E* Z1 T. [! B2 h/ }7 E! k! [ Y1 Q$ h5 R/ }/ s
慎用触发器
2 i- R1 h6 r, `5 V3 ?触发器功能强大,轻松可靠地实现许多复杂的功能,为什么又要慎用呢。 触发器本身没有过错,但由于我们的滥用会造成数据库及应用程序的维护困难。 $ X; X" B7 X* T B8 O! Q
1 L, i( \, B: m; B
在数据库操作中,我们可以通过关系、触发器、存储过程、应用程序等来实现数据操作,比如删除 T1 表记录时期望删除 T2 表相关的记录,此时可以建立级联删除的关系,也可以为 T1 表建立触发器使同时删除 T2 表相关记录,也可以自定义存储过程删除 T1 和 T2 表的记录,也可以在应用程序中使用两个 SQL 语句来删除……到底用哪一种好呢,应该说我们建立通过建立关系来实现级联删除是最好的,除非更有高的需求。
1 I9 P" [; ~$ O- K* Z
7 U, ^8 E4 Q; Z7 k7 ?触发器还有一个用途可以用来保障数据的完整性,但同时规则、约束、默认值也可以保障数据完整性,到底哪一个好呢,一般说来,较为简单的完整性要求我们不应该使用触发器。两者在运行机制上也是有区别的,像规则、约束、默认值这些是在数据更改之前进行数据验证,而触发器是在数据更改之后进行验证(如果事务回滚,该表将不会产生变化)。
- I! n3 i1 F( u5 Y; ]" b0 P/ f7 y9 I
总之,如果我们对触发器过分的依赖,就会造成遍地是程序的情况,因为触发器本身就需要别的程序给它一个触发条件,也就是说至少在两个地方存在着程序,同时我们抛弃了约束、默认值等而选用触发器,势必影响数据库的结构。
: T3 E/ Q! V# @5 c7 |0 r; j ^, ] T=============================================================================
4 I! i. `/ b. [, y0 u上面重点的部分我加了红色的标示。/ Y, X+ K, @) `2 \: [! N! D6 T! B! j
/ L, Z* D* `8 k D
具体到我们用的易飞ERP其实也不是难事:; E4 c8 s& V' B: K. y, ]
随便举个例子:! N/ _2 K/ U! I) ^
例:我希望用户在新增品号信息的同时,把这个品号的品名(MB002)更新到商品描述(MB009)字段当中。3 b& F$ T- n; N' s( r3 _* c
CREATE TRIGGER MB009_Insert --MB009_Insert 触发器的名称# V3 X* Z6 P+ N+ c+ D! M& D
ON [INVMB] --INVMB 数据表
8 W! `, D4 B( J, d: v) {FOR INSERT --关于INSERT 啥意思看上面的说明 :)
5 |# x' s% R2 u) ^/ SAS
. Z) h( x( m3 r' h9 L7 EDECLARE @MB001 VARCHAR(20) --定义变量
$ w' b5 e! ?& [3 IUPDATE INVMB SET % j6 x" g' G5 D) o8 }" _& @, y
MB009 = INVMB.MB002 % e: f O. K! y2 Y* V, J5 ]( {
FROM INVMB INNER JOIN INSERTED --INSERTED 啥意思在上面说明里面也写的很清楚了 我不再熬述
; d4 X+ h* _/ k: ?; d, zON INVMB.MB001=INSERTED.MB001" s; Z% U" y4 @8 `3 F& s
4 k' S/ _, V% @# m
其他的也都是大同小异,会不会关键是看自己愿不愿意学了。
: L6 Y1 N6 A* F/ a! G8 J3 v K" b
( T' v% e) u2 F' d5 E[ 本帖最后由 sunyesy 于 2007-11-3 14:20 编辑 ] |
-
4
查看全部评分
-
|