【问题标题】:What is the most portable way to check whether a trigger exists in SQL Server?检查 SQL Server 中是否存在触发器的最便携方法是什么?
【发布时间】:2010-10-12 19:05:13
【问题描述】:

我正在寻找最便携的方法来检查 MS SQL Server 中是否存在触发器。它至少需要在 SQL Server 2000、2005 和 2008 上运行。

该信息似乎不在 INFORMATION_SCHEMA 中,但如果它在某处,我更愿意从那里使用它。

我知道这种方法:

if exists (
    select * from dbo.sysobjects 
    where name = 'MyTrigger' 
    and OBJECTPROPERTY(id, 'IsTrigger') = 1
) 
begin

end

但我不确定它是否适用于所有 SQL Server 版本。

【问题讨论】:

    标签: sql-server triggers information-schema


    【解决方案1】:

    Sql Server Management Studio 生成:

    IF  EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N'[dbo].[RolesYAccesos2016_UsuariosCRM_trgAfterInsert]'))
    DROP TRIGGER [dbo].[RolesYAccesos2016_UsuariosCRM_trgAfterInsert]
    GO
    
    
    CREATE TRIGGER [dbo].[RolesYAccesos2016_UsuariosCRM_trgAfterInsert] 
    ON  [PortalMediadores].[dbo].[RolesYAccesos2016.UsuariosCRM]
    FOR INSERT
    AS  
    ...
    

    对于select @@version

    Microsoft SQL Server 2008 R2 (RTM) - 10.50.1797.0 (X64) 2011 年 6 月 1 日 15:43:18 版权所有 (c) Microsoft Corporation Enterprise Edition Windows NT 6.1(内部版本 7601:Service Pack 1)上的(64 位) (管理程序)

    【讨论】:

      【解决方案2】:

      这适用于 SQL Server 2000 及更高版本

      IF OBJECTPROPERTY(OBJECT_ID('{your_trigger}'), 'IsTrigger') = 1
      BEGIN
          ...
      END
      

      请注意,幼稚的逆向不能可靠地工作:

      -- This doesn't work for checking for absense
      IF OBJECTPROPERTY(OBJECT_ID('{your_trigger}'), 'IsTrigger') <> 1
      BEGIN
          ...
      END
      

      ...因为如果对象根本不存在,OBJECTPROPERTY 返回NULL,而NULL(当然)不是&lt;&gt; 1(或其他任何东西)。

      在 SQL Server 2005 或更高版本上,您可以使用 COALESCE 来处理该问题,但如果您需要支持 SQL Server 2000,则必须构建语句来处理三个可能的返回值:@987654329 @(对象根本不存在)、0(存在但不是触发器)或1(是触发器)。

      【讨论】:

      • Important Caveat: "不能使用 OBJECT_ID 查询非架构范围的对象,例如 DDL 触发器。" 在这些情况下,解决方法是使用@marc_s 在他的回答中描述的sys.triggers 视图。
      【解决方案3】:

      如果您尝试在 SQL Server 2014 上查找服务器范围的 DDL 触发器,您应该尝试 sys.server_triggers。

      IF EXISTS (SELECT * FROM sys.server_triggers WHERE name = 'your trigger name')
      BEGIN
          {do whatever you want here}
      END
      

      如果我告诉你任何不正确的地方,请告诉我。

      编辑: 我没有在其他版本的 SQL Server 上检查这个 dm。

      【讨论】:

        【解决方案4】:

        我会使用这种语法来检查和删除触发器

        IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[SCHEMA_NAME].[TRIGGER_NAME]') AND type in (N'TR'))
        DROP TRIGGER [SCHEMA_NAME].[TRIGGER_NAME]
        

        【讨论】:

          【解决方案5】:

          除了marc_s的出色回答:

          如果存在性检查旨在以某种方式删除或修改触发器之前,请使用直接 TSQL try/Catch bock,作为最快的方法。

          例如:

          BEGIN TRY
              DROP TRIGGER MyTableAfterUpdate;
          END TRY
          BEGIN CATCH
              SELECT ERROR_NUMBER() AS erno WHERE erno = 3701; -- may differ in SQL Server < 2005
          END CATCH;
          

          错误信息将是

          Cannot drop the trigger 'MyTableAfterUpdate', because it does not exist or you do not have permission.
          

          然后只需检查执行结果是否返回行,这在直接 sql 以及编程 API(C#,...)中很容易。

          【讨论】:

            【解决方案6】:

            经过测试,不能在 SQL Server 2000 上运行:

            select * from sys.triggers where name = 'MyTrigger'
            

            在 SQL Server 2000 和 SQL Server 2005 上测试并正常工作:

            select * from dbo.sysobjects
            where name = 'MyTrigger' and OBJECTPROPERTY(id, 'IsTrigger')
            

            【讨论】:

            • FWIW,您的 select * from dbo.sysobjects where name = 'MyTrigger' and OBJECTPROPERTY(id, 'IsTrigger') 不适用于我在 SQL-2000 上正常运行的 after insert, delete 触发器。该行在sysobjects 中,但其ID 上的OBJECTPROPERTY(id, 'IsTrigger')(作为上述的一部分或单独使用其原始ID)给出0。检查xtype = 'TR'type = 'TR' 有效。
            【解决方案7】:

            触发器名称在 SQL Server 中是否强制唯一?

            由于触发器根据定义应用于特定表,因此将搜索限制在相关表中不是更有效吗?

            我们有一个数据库,其中包含超过 30k 个表,所有这些表都至少有一个触发器,并且可能有更多(糟糕的数据库设计 - 很可能,但它在几年前是有意义的,并且不能很好地扩展)

            我用

            SELECT * FROM sys.triggers 
            WHERE [parent_id] = OBJECT_ID(@tableName) 
            AND [name] = @triggerName
            

            【讨论】:

              【解决方案8】:

              假设它是一个 DML 触发器:

              IF OBJECT_ID('your_trigger', 'TR') IS NOT NULL
              BEGIN
                  PRINT 'Trigger exists'
              END
              ELSE
              BEGIN
                  PRINT 'Trigger does not exist'
              END
              

              对于其他类型的对象(表、视图、键等),请参阅:http://msdn.microsoft.com/en-us/library/ms190324.aspx under 'type'。

              【讨论】:

              • 这会检查任何对象类型,而不仅仅是触发器。
              • 它打印'触发器存在',适用于 sql server 2012
              【解决方案9】:

              还有首选的“sys.triggers”目录视图:

              select * from sys.triggers where name = 'MyTrigger'
              

              或调用 sp_Helptrigger 存储过程:

              exec sp_helptrigger 'MyTableName'
              

              但除此之外,我想就是这样:-)

              马克

              更新(针对 Jakub Januszkiewicz):

              如果您需要包含架构信息,您还可以执行以下操作:

              SELECT
                  (list of columns)
              FROM sys.triggers tr
              INNER JOIN sys.tables t ON tr.parent_id = t.object_id
              WHERE t.schema_id = SCHEMA_ID('dbo')   -- or whatever you need
              

              【讨论】:

              • select * from sys.triggers where name = 'MyTrigger' 不适用于我的(正常工作等)触发器,而 wgw 的 IF OBJECTPROPERTY(OBJECT_ID('{your_trigger}'), 'IsTrigger') = 1 则... MSSQL 2008 R2。
              • @JakubJanuszkiewicz:当你运行这个时,你在正确的数据库中吗? sys.triggers 始终显示当前数据库中的触发器 - 它不会显示来自所有数据库的所有触发器...
              • @marc-s:我在正确的数据库中。我发现了问题 - sys.triggers 中的 name 列只是一个名称(没有架构名称),而 OBJECT_ID('...') 需要一个架构限定名称(至少如果架构是非默认名称,如果我理解正确)。所以在我将我的工作OBJECT_ID('MySchema.MyTrigger') 复制到select * from sys.triggers 之后,它没有工作。仅通过“MyTrigger”过滤即可。
              • @marc-s:顺便说一句,这也意味着如果您在数据库的不同模式中有多个同名触发器,select * from sys.triggers 会给您一个误报。类似于select * from sys.objects where type = 'TR' and schema_id = (select schema_id from sys.schemas where name = 'YourSchema') and name = 'YourTrigger' 的东西会得到正确的触发。
              • 这在 SQL Server 2000 中不起作用,正如问题所要求的那样,因为系统...目录视图是在 SQL Server 2005 中引入的。
              猜你喜欢
              • 1970-01-01
              • 2013-08-08
              • 2015-07-18
              • 2011-12-25
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-05-25
              • 2012-08-29
              相关资源
              最近更新 更多