SQL SERVER数据库开发之触发器的应用
作者:栽培者 来源:51js 发布时间:2008-06-23 13:09:00
不知道在坛子里有多少朋友使用触发器,如果你已经对触发器很了解了,那么请跳过此文,如果你还没有使用过触发器的话,那就让我们来认识一下吧。
相关阅读:SQL SERVER数据库开发之asp存储过程应用
触发器定义:
触发器是一种特殊类型的存储过程,不由用户直接调用。当使用下面的一种或多种数据修改操作在指定表中对数据进行修改时,触发器会生效:Update、Insert 或 Delete。触发器可以查询其它表,而且可以包含复杂的 SQL 语句。它们主要用于强制复杂的业务规则或要求。
触发器一个应用就是保持和维护数据的完整性及合法性,那么怎么来理解呢?就是说你可以在程序里提交任意数据,然后由触发器来判断数据的完整性及合法性,当然这里只是举例说明,实际应用中不推荐这样用,应该由应用程序来验证数据的完整性及合法性。
下面我还是以实例的方式来描述触发器的应用。
设:当前数据库中有“uMateriel”和“uRecord”两张表,他们分别用来保存物品信息和物品的出入库记录信息,结构如下
uMateriel
----------------
mId int
mName nvarchar(40)
mNum int DEFAULT 0
uRecord
----------------
rId int
mId int
rNum int
rDate datetime DEFAULT GetDate()
rMode bit DEFAULT 0
好了,数据表已经有了,现在看一下实际的应用。
现在,我们要购入物品A,数量100,时间为当天,已知物品A的编号为1,那么通常我们需要做以下两个步骤:
1、在 uRecord 记录表中增加一条物品A的购入记录:
Insert INTO uRecord (mId, rNum, rMode) VALUES (1, 100, 0)
2、更新 uMateriel 物品库存表中物品A的数量:
Update uMateriel SET mNum = mNum + 100 Where mId=1
也就是说代码中要先后处理以上两条语句,才能保证库存的准确性,以ASP代码为例:
On Error Resume Next
'// 设 adoConn 为已经连接的 ADODB.Connection 对象
With adoConn
'// 事务开始,因为涉及到多步数据更新操作,所以在这里使用事务
.BeginTrans
'// 插入物品入库记录
.Execute("Insert INTO uRecord (mId, rNum, rMode) VALUES (1, 100, 0)")
'// 更新物品库存记录
.Execute("Update uMateriel SET mNum = mNum + 100 Where mId=1")
'// 判断是否产生了错误
If Err.Number <> 0 Then
'// 如果有错误,事务回滚
.RollbackTrans
Response.Write "错误!"
Err.Clear
Else
'// 如果没有错误,则提交事务
.CommitTrans
End If
End With
以上代码可以更新一条入库记录了,但是我们今天要了解的是触发器的应用,那么要在触发器里写什么内容可以简化以上代码呢?下面来创建一个触发器。
创建触发器的语法很长,简化为:
Create TRIGGER 触发器名 ON 表名/视图名
{ FOR | AFTER | INSTEAD OF } { [Delete] [,] [Insert] [,] [Update] }
AS
触发器内容(SQL 语句)
SQL SERVER 联机丛书的描述:
AFTER
指定触发器只有在触发 SQL 语句中指定的所有操作都已成功执行后才激发。所有的引用级联操作和约束检查也必须成功完成后,才能执行此触发器。
如果仅指定 FOR 关键字,则 AFTER 是默认设置。
不能在视图上定义 AFTER 触发器。
INSTEAD OF
指定执行触发器而不是执行触发 SQL 语句,从而替代触发语句的操作。
在表或视图上,每个 Insert、Update 或 Delete 语句最多可以定义一个 INSTEAD OF 触发器。然而,可以在每个具有 INSTEAD OF 触发器的视图上定义视图。
INSTEAD OF 触发器不能在 WITH CHECK OPTION 的可更新视图上定义。如果向指定了 WITH CHECK OPTION 选项的可更新视图添加 INSTEAD OF 触发器,SQL Server 将产生一个错误。用户必须用 Alter VIEW 删除该选项后才能定义 INSTEAD OF 触发器。
{ [Delete] [,] [Insert] [,] [Update] }
是指定在表或视图上执行哪些数据修改语句时将激活触发器的关键字。必须至少指定一个选项。在触发器定义中允许使用以任意顺序组合的这些关键字。如果指定的选项多于一个,需用逗号分隔这些选项。
对于 INSTEAD OF 触发器,不允许在具有 ON Delete 级联操作引用关系的表上使用 Delete 选项。同样,也不允许在具有 ON Update 级联操作引用关系的表上使用 Update 选项。
现在根据上面的语法我们建立一个触发器(注意一点,触发器是附于一张表或视图的,所以只能在表里建立或在查询分析器里建立),这个触发器的功能就是自动更新库存数量
Create TRIGGER [trUpdateMaterielNum] ON [dbo].[uRecord]
-- 表明在插入记录之后执行这个触发器
AFTER Insert
AS
-- 当前更新的编号
DECLARE @intID int
-- 当前更新的数量
DECLARE @intNum int
-- 当前模式
DECLARE @intMode int
-- 判断是否有记录录被更新,@@ROWCOUNT是系统函数,返回受上一语句影响的行数。
IF @@ROWCOUNT >0
BEGIN
-- 取得当前插入的物品编号和数量,Inserted 表用于存储 Insert 和 Update 语句所影响的行的副本。
Select @intID=mId,@intNum=rNum,@intMode=rMode FROM Inserted
-- 判断当前模式(0为入库,1为出库)来更新当前物品的数量
IF @intMode = 0
Update uMateriel SET mNum = mNum + @intNum Where mId=@intID
ELSE
Update uMateriel SET mNum = mNum - @intNum Where mId=@intID
END
我们现在来了解一下这个触发器,首先使用 Create TRIGGER 语句定义一个基于 uRecord 表的触发器 trUpdateMaterielNum,AFTER Insert 表明这个触发器会在插入记录之后执行,也就是说当我们在程序里执行 Insert INTO uRecord (mId, rNum, rMode) VALUES (1, 100, 0) 这条语句之后,trUpdateMaterielNum这个触发器里的内容就会被自动执行,也就是说库存将会被自动更新了。现在我们更改一下ASP的代码
On Error Resume Next
'// 设 adoConn 为已经连接的 ADODB.Connection 对象
'// 插入物品入库记录
adoConn.Execute("Insert INTO uRecord (mId, rNum, rMode) VALUES (1, 100, 0)")
'// 判断是否产生了错误
If Err.Number <> 0 Then
Response.Write "错误!"
Err.Clear
End If
是不是简化了很多呢,是的,在这里已经不用考虑库存方面,只需要插入流水帐就可以了,库存更新就交由触发器来处理。
以上的例子是触发器的其中一个应用,在触发器的参数中还有 Delete、Update,他们分别在删除和更新时或之后执行。下面看一个删除时的触发器例子。
我们在数据库中增加一个表,用来记录日志,其结构如下
uSysLog
--------------
lId int
lEvent nvarchar(200)
lTime datetime DEFAULT GetDate()
现在假设这张表是用来记录系统的日志用的,当我们删除一条流水帐时,往日志表里记录一条事件,那么我们来创建一个基于 uRecord 表的删除时的触发器
Create TRIGGER [trDeleteRecord] ON [dbo].[uRecord]
-- 表明在插入记录之后执行这个触发器
FOR Delete
AS
-- 当前删除的流水号
DECLARE @intID int
-- 当前删除的数量
DECLARE @intNum int
-- 当前模式
DECLARE @intMode int
-- 判断是否有记录录被更新,@@ROWCOUNT是系统函数,返回受上一语句影响的行数。
IF @@ROWCOUNT >0
BEGIN
-- 取得当前删除的行信息,Deleted 表用于存储 Delete 和 Update 语句所影响的行的复本。
Select @intID=rId,@intNum=rNum,@intMode=rMode FROM Deleted
-- 向日志表中插入一条简单的删除事件日志
Insert INTO uSysLog (lEvent) VALUES ('用户删除了流水号为:' + CAST(@intID as nvarchar(20) + ',数量:' + CAST(@intNum as nvarchar(20) + ',方向:' + CASE @intMode WHEN 0 THEN '入库' ELSE '出库' END)
END
建立好触发器后,现在只要我们删除 uRecord 表中的一条记录,就会在系统日志中增加一条事件日志。
通过以上简单的介绍,希望原来没有使用过触发器的朋友能对触发器有个大致的概念和印象,如果你要深入了解的话,SQL SERVER联机丛书就是你的好帮手,那么触发器的简单应用就介绍到这儿了。


猜你喜欢
- 目录mapfiltersomeeveryfindIndexpipe参考答案一、返回函数接受一个参数二、返回函数接受不定参数实现 lodash
- 一、报错信息:【file】【Default Settint】---Project Interpreter 点击搜索suds安装模块报错解决:
- CSS 文件的大小和所引起的 HTTP 的请求数是 CSS 性能的最关键因素回流(reflow)和渲染时间(非常!)没那么重要副本(dupl
- function create5StarClip(context) { var n = 0; var dx = 100; var dy =
- 前言这篇文章通过实例给大家讲解Python3中print带颜色输出的格式,下面话不多说了,来一起看看详细的介绍吧\033[显示方式;前景色;
- 初学框架vue搭配vux使用发现这个UI库使用有些力不从心。下面说说自己在表单验证过程遇到的两个需求问题及解决的方法。1.使用x-input
- 第一步:要使用vant组件安装好vant,npm i vant -S第二步:在你要用到的地方js中引入或者在src/main.js里面引入i
- 之前一直没弄清jsonArray和jsonObject的区别,今天终于弄明白了。jsonArray是数组,以[ ]包含数据,jsonObje
- 前言:写小程序时,遇到个需要自定义回归时间的场景,下面是实现的效果图。 于我需求而言,我只需要用到fixed_in
- 理论介绍分词是自然语言处理的一个基本工作,中文分词和英文不同,字词之间没有空格。中文分词是文本挖掘的基础,对于输入的一段中文,成功的进行中文
- 1. 引言Python程序有许多模块和第三方包,这非常有助于高效编程。了解这些模块的正确使用方法是很重要的,在本文中,主要介绍一些非常实用的
- 1)doctest 使用doctest是一种类似于命令行尝试的方式,用法很简单,如下 def f(n): ""
- 1. 引言词云图可以让我们方便地识别出文本中的关键词,其中单词的大小代表它们的频率。有了这个,我们甚至在阅读之前就可以很好地了解文本的内容。
- 计算机视觉方面朋友都需要跟图像打交道,在pytorch中图像与我们平时在matlab中见到的图像数据格式有所不同。matlab中我们通常使用
- 如何获取指定元素在想要获取元素上添加“ref” ref="scroll&quo
- 本文介绍MySQL数据库中执行select查询语句,查询指定列的数据,即指定字段的数据。再来回顾一下SQL语句中的select语句的语法:S
- <html> <head> <script type="text/javascript"&
- 目录Show Me The Code测试下效果效果PS另一种方法Show Me The CodeHTMLElement.prototype.
- 我见朋友可以把数据库的记录显示到列表框里去,挺实用,也想做一个。怎么做啊?这简单,代码和说明如下:dblist.asp<html>
- Go 语言相比Java等一个很大的优势就是可以方便地编写并发程序。Go 语言内置了 goroutine 机制,使用goroutine可以快速