• sql笔记(4)触发器


    --================================================
    -- 触发器
    --================================================
    /*
    *如何创建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

  • 相关阅读:
    芯片测试
    【转】悬浮的对话框
    imagebutton 设置点击和按压效果
    imagebutton 设置了src属性的图片更换
    侧滑实现
    使用自定义的AlertDialog。
    [转]Dialog
    【转】webview的几个问题
    webview 播放H5视频问题 黑屏 只有声音没有画面
    【转】Android HTML5 Video视频标签自动播放与自动全屏问题解决
  • 原文地址:https://www.cnblogs.com/top100/p/2092749.html
Copyright © 2020-2023  润新知