sql触发器的用法

sql触发器的用法

触发器:是一种特殊类型的存储过程,不由用户直接调用,也不是手工启动,而是由事件来触发,比如当对一个表进行操作(Insert,Delete,Update)。创建触发器时会对其进行定义,以便在对特定表或列做特定类型的数据修改时执行。

  使用触发器的优点:1.触发器是MySQL服务器上自动提供的

                           2.触发器可以查询多张表,而且可以包含复杂的SQL语句。

  以一个牛腩新闻系统上的一个例子简单介绍触发器的使用:

                         要求: 删除新闻类别,同时删除新闻类别下的新闻内容和新闻评论,这样的操作涉及到三张表的操作                                                 (Category、News、Comment),如果用SQL语句是很难实现的。

 

/*
*如何创建After DML触发器
*如何创建Instead Of DML触发器
*如何创建DDL触发器
*如何修改和删除既有触发器
*如何启用和禁用触发器
*如何限制触发器嵌套、设置触发器顺序和控制递归
*如何查看触发器元素据
*/
--1、DML触发器
--A、After DML触发器是在对表的insert,update和delete修改操作成功完成后执行
--语法:

/*
Trigger on an INSERT, UPDATE, or DELETE statement to a table or view (DML Trigger)
CREATE TRIGGER [ schema_name . ]trigger_name
ON { table | view }
[ WITH <dml_trigger_option> [ ,...n ] ]
{ FOR | AFTER | INSTEAD OF }
{ [ INSERT ] [ , ] [ UPDATE ] [ , ] [ DELETE ] }
[ WITH APPEND ]
[ NOT FOR REPLICATION ]
AS { sql_statement  [ ; ] [ ...n ] | EXTERNAL NAME <method specifier [ ; ] > }

<dml_trigger_option> ::=
    [ ENCRYPTION ]
    [ EXECUTE AS Clause ]
*/

--使用触发器来跟踪Production.ProductInventory表的行的插入和删除

--跟踪所有的插入、更新和删除操作

create table Production.ProductInventoryAudit
(
 ProductID int not null,
 LocationID smallint not null,
 Shelf nvarchar(10) not null,
 Bin tinyint not null,
 Quantity smallint not null,
 rowguid uniqueidentifier not null,
 ModifiedDate datetime not null,
 InsOrUPD char(1) not null
)

go

--创建触发器来填充Production.ProductInventoryAudit表

create trigger Production.trg_uid_ProductInventoryAudit
on Production.ProductInventory
after insert,delete
as

set nocount on --屏蔽触发器触发时"受影响行数"消息返回给调用的应用程序

--插入行

insert Production.ProductInventoryAudit
(ProductID,LocationID,Shelf,Bin,Quantity,rowguid,ModifiedDate,InsOrUPD)
select Distinct i.productID,i.LocationID,i.Shelf,i.Bin,i.Quantity,i.rowguid,getdate(),'I'
from inserted i

--删除的行

insert Production.ProductInventoryAudit
(ProductID,LocationID,Shelf,Bin,Quantity,rowguid,ModifiedDate,InsOrUPD)
select Distinct d.productID,d.LocationID,d.Shelf,d.Bin,d.Quantity,d.rowguid,getdate(),'D'
from deleted d
go

--插入一个新行
insert production.ProductInventory
(ProductID,LocationID,Shelf,Bin,Quantity) values(316,6,'A',4,22)

--删除一行
delete Production.ProductInventory where ProductID=316 and LocationID=6

--检测审核表
select ProductID,LocationID,InsOrUPD from Production.ProductInventoryAudit

--select * from production.ProductInventory
--select * from Production.Product
--B、创建Instead of DML触发器
--Instead of触发器的执行替代触发触发器的原始数据修改操作,并对表和视图都允许
--通常用于处理不允许进行数据修改的视图的数据修改操作

--示例:创建一个新表来保存HumanResources.Department表"等待批准pending approval"
--行。这些是需要经理的批准才能加入正式表的新部门。创建一个视图来显示来呢两个表中所有
--"已批准"和"等待批准"的部门,然后会在视图上创建一个Instead of触发器,导致插入的行
--会被转到新的审批表,而不是HumanResources.Department表:

--创建部门"审批"表

create table HumanResources.DepartmentApproval
(
 Name nvarchar(50) not null unique,
 GroupName nvarchar(50) not null,
 ModifiedDate datetime not null default getdate()
)
go

--创建视图来查看已批准的和待批准的部门
create view HumanResources.vw_Department
as
select Name,GroupName,ModifiedDate,'Approved' Status
from HumanResources.Department
union
select Name,GroupName,ModifiedDate,'Pending Approval' Stuatus
from HumanResources.DepartmentApproval

go

--在新视图上创建Instead of触发器
create Trigger HumanResources.trg_vw_Department
on HumanResources.vw_Department
instead of insert
as
 set nocount on
 insert HumanResources.DepartmentApproval(Name,GroupName)
 select i.Name,i.GroupName from inserted i
 where i.Name not in(select Name from HumanResources.DepartmentApproval)
go

--向视图插入行
insert HumanResources.vw_Department
(Name,GroupName) values('Print Production','Manufacturing')

--检查视图的内容

select Status,Name
from HumanResources.vw_Department where GroupName='Manufacturing'

--select * from HumanResources.Department
--select * from HumanResources.DepartmentApproval

--C、使用DML触发器和事务

alter trigger Production.trg_uid_ProductInventoryAudit1
on Production.ProductInventory after insert,delete
as

set nocount on
if exists(select Shelf from inserted where Shelf='A')

begin

 print 'Shelf ''A'' is closed for new inventory.'
 rollback
end

--插入的行
insert Production.ProductInventoryAudit
(ProductID,LocationID,Shelf,Bin,Quantity,rowguid,ModifiedDate,InsOrUPD)
select distinct i.ProductID,i.LocationID,i.Shelf,i.Bin,i.Quantity,i.rowguid,getdate(),'I'
from inserted i

--删除的行

insert Production.ProductInventoryAudit
(
 ProductID,LocationID,Shelf,Bin,Quantity,rowguid,ModifiedDate,InsOrUPD
)
select d.ProductID,d.LocationID,d.Shelf,d.Bin,d.Quantity,d.rowguid,getdate(),'D'
from deleted d

if exists
(
 select Quantity from deleted where Quantity>0
)
begin
 print '你不能删除有确定数量的行!'
 rollback
end
go

--使用Shelf'A'插入新行来测试
insert Production.ProductInventory(ProductID,LocationID,Shelf,Bin,Quantity)
values(316,6,'A',4,22)

--使用显式事务演示两个删除

begin transaction
--删除0数量的行
delete Production.ProductInventory where ProductID=853 and LocationID=7

--删除非0数量的行
delete Production.ProductInventory where ProductID=999 and LocationID=60

commit transaction

--因为触发器发起了回滚,所以外部事务也结束了,所以同一事务中行没有被删除

select ProductID,LocationID from Production.ProductInventory
where (ProductID=853 and LocationID=7) or (ProductID=999 and LocationID=60)

--D、查看DML触发器的元数据

--演示查看当前数据库教程中有关触发器的信息

select object_name(parent_id) Table_or_ViewNM,
name TriggerNM,is_instead_of_trigger,is_disabled
from sys.triggers
where parent_class_desc='Object_or_column'
order by object_name(parent_id),name

--显示某个触发器的T-SQL定义,可以查询sys.sql_modules
select o.name,m.definition
from sys.sql_modules m
inner join sys.objects o
on m.object_id=o.object_id where o.type='TR'

--2、DDL触发器

--SQL Server2005引入DDL触发器是对服务器活数据库事件做出响应,而不是表数据
--修改
--语法:
/*
Trigger on a CREATE, ALTER, DROP, GRANT, DENY, REVOKE, or UPDATE STATISTICS statement (DDL Trigger)
CREATE TRIGGER trigger_name
ON { ALL SERVER | DATABASE }
[ WITH <ddl_trigger_option> [ ,...n ] ]
{ FOR | AFTER } { event_type | event_group } [ ,...n ]
AS { sql_statement  [ ; ] [ ...n ] | EXTERNAL NAME < method specifier >  [ ; ] }

<ddl_trigger_option> ::=
    [ ENCRYPTION ]
    [ EXECUTE AS Clause ]

<method_specifier> ::=
    assembly_name.class_name.method_name
*/
--A、创建审核服务器级别的事件的DDL触发器

--创建DDL触发器
use master
go
--不允许在SQL实例上有新的登录

create trigger srv_trg_RestricNewLogins on all server
for create_login
as
print '禁止创建新登录'
 rollback
go

--试图增加新的SQL登录:
create Login Joes with password='A235921'
go
--B、创建审核数据库级别的事件的DDL触发器
--创建审核表
create table dbo.ChangeAttempt
(
EventData xml not null,
AttemptDate datetime not null default getdate(),
DBUser char(50) not null
)
go
--创建一个数据库DDL触发器来跟踪索引操作,插入事件数据到新创建的表中:

create trigger db_trg_RestrictIndexChanges
on database
for create_index,alter_index,drop_index
as
set nocount on
--EVENTDATA()函数以XML格式返回服务器和数据事件信息
insert dbo.ChangeAttempt(EventData,DBUser) values(EVENTDATA(),User)
go

--在数据库中建立真实的索引

create nonclustered index in_ChangeAttempt_DBUser on dbo.ChangeAttempt(DBUser)
go
select * from dbo.ChangeAttempt

--C、查看DDL触发器元数据

--显示当前数据库中的DDL触发器
select name TriggerNM,is_disabled
from sys.triggers
where parent_class_desc='DATABASE'
order by object_name(parent_id),name

--查询服务器级别触发器数据

select name,s.type_desc SQL_or_CLR,
is_disabled,e.type_desc FiringEvents
From sys.server_triggers s
inner join sys.server_trigger_events e on
s.object_id=e.object_id

--查询数据库范围的DDL触发器的T-SQL定义

select t.name,m.Definition
from sys.triggers as t
inner join sys.sql_modules m on t.object_id=m.object_id
where t.parent_class_desc='database'

--要显示服务期范围内的DDL触发器

select t.name,m.definition
from sys.server_sql_modules m
inner join sys.server_triggers t on
m.object_id=t.object_id

--3、管理触发器

--修改触发器

--修改触发器,这次不会限制用户创建新的登录名,而是允许登录名事件,之后是一条警告和对审核表进行insert
alter trigger srv_trg_RestricNewLogins
on all server
for create_login
as
set nocount on
print '你创建登录将被监视'
insert AdventureWorks.dbo.ChangeAttempt
(EventData,DBUser) values(EVENTDATA(),user)

go

--启用和禁止触发器

create trigger HumanResources.trg_Department
on HumanResources.Department
after insert
as
print N'触发器被激活'
go

disable trigger HumanResources.trg_Department
on HumanResources.Department
--因为触发器被禁止了,所以下面的Insert执行后不会返回打印消息

insert HumanResources.Department(name,GroupName) values('Construction','Building Services')

go

--enable trigger命令启用触发器
enable trigger HumanResources.trg_Department
on HumanResources.Department

--再次插入
insert HumanResources.Department
(Name,GroupName)
values('Cleaning1','Building Services')

--限制触发器嵌套

/*
 当触发器触发之后执行的动作会触发另一个触发器,那个触发器然后又触
 发另外一个触发器的时候就发生了触发器嵌套
 SQL Server 2005最大嵌套级别是32层
*/

--禁止和启用触发器嵌套

use master
go

--禁止嵌套
exec sp_configure 'nested triggers',0
reconfigure with override  --由于服务器选项包含当前的配置和运行的配置,此命令用于更新运行时值以使之立即生效
go

--启用嵌套

exec sp_configure 'nested trigger',1
reconfigure with override
go

--控制触发器递归

/*
如果触发器触发后执行的行为会导致相同的表触发器再次触发,那么这种触发器嵌套就被认为是递归的。当触发器的触发影响
其他表的时候,如果触发器还会影响原始表,引起原来的触发器再次触发,也会发生递归
*/

--启用和禁止递归触发器

alter database AdventureWorks  --是否允许数据库内递归触发器
set recursive_Triggers on

--查看数据库设置

select is_recursive_triggers_on
from sys.databases

where name='AdventureWorks'

--防止递归
alter database AdventureWorks
set recursive_triggers off

--查看数据库设置
select is_recursive_triggers_on
from sys.databases
where name='AdventureWorks'

--设置触发器触发次序

--创建一个测试表并为之增加3个DML的Insert触发器,然后使用sp_settrigger来定义触发器次序

create table dbo.TestTriggerOrder
(
 TestID int not null
)
go

create trigger dbo.trg_i_TestTriggerOrder
on dbo.TestTriggerOrder
after insert
as
print N'我将被第一个触发'
go

create trigger dbo.trg_i_TestTriggerOrder2
on dbo.TestTriggerOrder
after insert
as
print N'我将最后被触发'
go
create trigger dbo.trg_i_TestTriggerOrder3
on dbo.TestTriggerOrder
after insert
as
print N'我将不是第一个也不是最后一个被触发'
go

exec sp_settriggerorder 'trg_i_TestTriggerOrder','First','INSERT'
exec sp_settriggerorder 'trg_i_TestTriggerOrder2','Last','INSERT'

insert dbo.TestTriggerOrder values(2);
go

--删除触发器

--删除DML触发器
drop trigger dbo.trg_i_TestTriggerOrder
--删除多个触发器

Drop trigger dbo.trg_i_TestTriggerOrder2,dbo.trg_i_TestTriggerOrder3

--删除DDL触发器

Drop trigger db_trg_RestrictIndexChanges

实例

USE [NewsSystem]GO/****** Object: 
Trigger [dbo].[trigCategoryDelete]   
Script Date: 06/24/2011 19:31:14 ******/
SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGO-- =============================================--
 Author:李颖杰   
<Author,,Name>-- Create date: 2011-06-22-- Description:   
删除类别触发器--
=============================================
ALTER TRIGGER [dbo].[trigCategoryDelete]  
ON  [dbo].[Category]  
instead of DELETEAS BEGIN 
declare @caId int  select @caId=id from deleted   
--删除评论
 delete comment where newsId in(select newsId  from news where caId=@caId) 
--删除新闻  delete news where caId=@caId 
--删除类别  delete category where id=@caId    
 SET NOCOUNT ON;
end

时间: 2024-09-19 13:57:58

sql触发器的用法的相关文章

sql 触发器trigger 创建与用法

sql 触发器trigger 创建与用法 发器也是一种带名的pl/sql块.触发器类似于过程和函数,因为它们都是拥有声明 .执行和异常处理过程的带名pl/sql块.与包类似,触发器必须存储在数据库教程中并 且不能被块进行本地化声明. 对于触发器而言,当触发事件发生的时候就会显式地执行该触发器,并且触发器不 接受参数   create table employee( 2>     id          int, 3>     name        nvarchar (10), 4>  

如何使用SQL触发器进行备份数据库?

sql|触发器|备份|数据库 首先,你需要建立测试数据表,一个用于插入数据:test3,另外一个作为备份:test3_bak 以下是引用片段为例: create table test3(id int primary key not null identity(1,1),uname varchar(20),uage int); create table test3_bak(id int primary key not null identity(1,1),bid int,uname varchar

SQL触发器实例讲解

SQL触发器实例1 定义: 何为触发器?在SQL Server里面也就是对某一个表的一定的操作,触发某种条件,从而执行的一段程序.触发器是一个特殊的存储过程.  常见的触发器有三种:分别应用于Insert , Update , Delete 事件.  我为什么要使用触发器?比如,这么两个表: 复制代码代码如下: Create Table Student( --学生表  StudentID int primary key, --学号  ....  )  Create Table BorrowRec

sql触发器结果没有更新

问题描述 sql触发器结果没有更新 create trigger tr_cost on stu_inf for updateas declare @bukao intbegin select @bukao=补考次数from v_cost if @bukao>=2 begin update stu_inf set 学习费用=学习费用 * 1.1 where 学员编号 in(select 学员编号 from stu_inf) end end # 请问这个触发器为什么在表中没有显示结果,stu_inf

sqlserver 存储过程- 新手请求帮助SQL触发器

问题描述 新手请求帮助SQL触发器 set ANSI_NULLS ON set QUOTED_IDENTIFIER ON go ALTER TRIGGER [tr_yskq1] ON [dbo].[yskq1] FOR INSERT AS declare @bh varchar(10), @date1 datetime, @time1 varchar(30), @timeA varchar(30), @timeB varchar(30), @bmmc varchar(50), @jh bigin

sqlserver2008触发器-SQL触发器进行更新操作时 用insert添加发生主键冲突

问题描述 SQL触发器进行更新操作时 用insert添加发生主键冲突 环境:SQLserver 2008 创建的表 --库存表(还有多少商品)ID 名称 库存数量 --销售表(卖了多少商品)ID 销售数量 create table StockInfo ( ProID int primary key identity(1,1), ProName nvarchar(20) not null, ProNumber int not null ) go create table SellTab--销售表

sql 触发器问题!求帮忙啊

问题描述 sql 触发器问题!求帮忙啊 使用触发器控制表插入操作时某个字段不能为空,如果为空回滚操作. 这个怎么搞!! 解决方案 很简单啊,直接设置字段不为空就行了 解决方案二: 这个为什么用触发器,在建表的时候就设置该字段不能为空

SQL 触发器批量删除数据

问题描述 SQL 触发器批量删除数据 有A主表,B表为临时表两个表,两个表的结构完全相同,主键分别为ch_billno,ch_tableno,ssid,我想做一个触发器,当A表插入主键数据时,把临时表中存在相同主键的数据删除,插入数据的时候会用到sqlbulkcopy方式插入,只会引发一次insert操作. 解决方案 亲测可用, 楼主速速采纳吧, 呵呵 --1. 创建测试表 A,B 及测试数据 IF OBJECT_ID('dbo.A') IS NOT nuLL BEGIN DROP TABLE

SQL触发器在插入记录中根据A字段自动给B字段赋值

问题描述 SQL触发器在插入记录中根据A字段自动给B字段赋值 假如我有一个人员信息表,表的字段结构如下: 姓名 性别 性别值 性别字段,如果为男,性别值为0: 性别字段,如果为女,性别值为1: 性别字段,如果为中性,性别值为3: 在插入记录的时候,只会插入 姓名和性别两个字段.现在想要通过触发器来自动填充后面一个'性别值'字段. 这个如何实现呢?求指导.插入的时候,可能一次性插入多条记录. (MSSQL 2008数据库) 解决方案 sqlserver貌似是不支持oracle的for each r