热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

sql触发器的用法

sql的用法触发器:是一种特殊类型的存储过程,不由用户直接调用,也不是手工启动,而是由事件来触发,比如当对一个表进行操作(Insert,Delete,Update)。创建触发器时会对其进行定义,以便在对特定表或列做特定类型的数据修改时执行。 使用触发器的优点:1.触发器是MySQL服务器上自动提供的     &
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 [ ,...n ] ]
{ FOR | AFTER | INSTEAD OF }
{ [ INSERT ] [ , ] [ UPDATE ] [ , ] [ DELETE ] }
[ WITH APPEND ]
[ NOT FOR REPLICATION ]
AS { sql_statement [ ; ] [ ...n ] | EXTERNAL NAME }

::=
[ 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)
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 [ ,...n ] ]
{ FOR | AFTER } { event_type | event_group } [ ,...n ]
AS { sql_statement [ ; ] [ ...n ] | EXTERNAL NAME [ ; ] }

::=
[ ENCRYPTION ]
[ EXECUTE AS Clause ]

::=
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:李颖杰
-- 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

推荐阅读
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 一、Hadoop来历Hadoop的思想来源于Google在做搜索引擎的时候出现一个很大的问题就是这么多网页我如何才能以最快的速度来搜索到,由于这个问题Google发明 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • 本文介绍了如何在MySQL中将零值替换为先前的非零值的方法,包括使用内联查询和更新查询。同时还提供了选择正确值的方法。 ... [详细]
  • 本文介绍了使用AJAX的POST请求实现数据修改功能的方法。通过ajax-post技术,可以实现在输入某个id后,通过ajax技术调用post.jsp修改具有该id记录的姓名的值。文章还提到了AJAX的概念和作用,以及使用async参数和open()方法的注意事项。同时强调了不推荐使用async=false的情况,并解释了JavaScript等待服务器响应的机制。 ... [详细]
  • PHP设置MySQL字符集的方法及使用mysqli_set_charset函数
    本文介绍了PHP设置MySQL字符集的方法,详细介绍了使用mysqli_set_charset函数来规定与数据库服务器进行数据传送时要使用的字符集。通过示例代码演示了如何设置默认客户端字符集。 ... [详细]
  • 本文介绍了在Hibernate配置lazy=false时无法加载数据的问题,通过采用OpenSessionInView模式和修改数据库服务器版本解决了该问题。详细描述了问题的出现和解决过程,包括运行环境和数据库的配置信息。 ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • 本文介绍了在SpringBoot中集成thymeleaf前端模版的配置步骤,包括在application.properties配置文件中添加thymeleaf的配置信息,引入thymeleaf的jar包,以及创建PageController并添加index方法。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • ZSI.generate.Wsdl2PythonError: unsupported local simpleType restriction ... [详细]
  • 本文介绍了高校天文共享平台的开发过程中的思考和规划。该平台旨在为高校学生提供天象预报、科普知识、观测活动、图片分享等功能。文章分析了项目的技术栈选择、网站前端布局、业务流程、数据库结构等方面,并总结了项目存在的问题,如前后端未分离、代码混乱等。作者表示希望通过记录和规划,能够理清思路,进一步完善该平台。 ... [详细]
  • Android开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
author-avatar
fffas2010_734_196
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有