如何添加"IF NOT EXISTS"来创建触发语句

How to add "IF NOT EXISTS" to create trigger statement

我正在使用 sql 服务器 2008 R2。更具体地说,Microsoft SQL Server 2008 R2 (RTM) - 10.50.1600.1 (X64) Apr 2 2010 15:48:46 Copyright (c) Microsoft Corporation Standard Edition (64-bit) o​​n Windows NT 6.1(内部版本 7601:Service Pack 1)(管理程序)。我是 sql 服务器和 procedures/triggers 的新手。我有以下代码来创建触发器(有效):

CREATE TRIGGER [dbo].[Insert_WithdrawalCodes] 
   ON  [dbo].[PupilWithdrawalReason] 
   AFTER INSERT
AS 
BEGIN
    SET NOCOUNT ON;
        UPDATE [dbo].[PupilWithdrawalReason] SET DateCreated=dbo.SYSTEMTIME() 
        WHERE WithdrawalCodeID IN (SELECT WithdrawalCodeID FROM inserted)
END

如何仅在触发器尚不存在时有条件地创建?我在这里做错了什么? Whosebug 有很好的 IF NOT EXISTS 示例,但我无法将其与 CREATE 结合使用。这是我失败的努力之一:

IF NOT EXISTS (SELECT * FROM sys.objects WHERE type = 'TR' AND name = 'Insert_WithdrawalCodes')
   exec('CREATE TRIGGER [dbo].[Insert_WithdrawalCodes] ON  [dbo].[PupilWithdrawalReason] AFTER INSERT AS BEGIN SET NOCOUNT ON; UPDATE [dbo].[PupilWithdrawalReason] SET DateCreated=dbo.SYSTEMTIME() WHERE WithdrawalCodeID IN (SELECT WithdrawalCodeID FROM inserted) END')
GO

最好的方法是在创建对象之前检查对象并删除它们(如果存在)。

如果它存在,我宁愿不创建它,我会以另一种方式处理它,如果存在则删除它,然后再创建。

通常在冗长的脚本中,如果您想更新触发器的定义,只需将其添加到该脚本的末尾,您的触发器定义就会更新。

所以方法应该是 create the object but drop it if it already exists 而不是 dont create it at all if it already exists

IF OBJECT_ID ('[Insert_WithdrawalCodes] ', 'TR') IS NOT NULL
   DROP TRIGGER [Insert_WithdrawalCodes];
GO

CREATE TRIGGER .......
IF EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N'[dbo].[TRIGGERNAME]'))
DROP TRIGGER [dbo].[TRIGGERNAME]
go
IF  EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[TABLENAME]') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)
BEGIN
CREATE   TRIGGER [dbo].[TRIGGERNAME] ON [dbo].[TABLENAME] FOR INSERT, UPDATE 

AS ...

END

根据您更新后的问题...试试这个:

IF NOT EXISTS (select * from sys.objects where type = 'TR' and name = 'Insert_WithdrawalCodes')
EXEC dbo.sp_executesql @statement = N'

CREATE TRIGGER [dbo].[Insert_WithdrawalCodes] 
   ON  [dbo].[PupilWithdrawalReason] 
   AFTER INSERT
AS 
BEGIN
    SET NOCOUNT ON;
        UPDATE [dbo].[PupilWithdrawalReason] SET DateCreated=dbo.SYSTEMTIME() 
        WHERE WithdrawalCodeID IN (SELECT WithdrawalCodeID FROM inserted)
END


 '

像 CREATE TRIGGER 这样的某些语句需要成为批处理中的第一个(例如,由 GO 分隔的语句组)。

https://msdn.microsoft.com/en-us/library/ms175502.aspx

或者你可以这样做

IF NOT EXISTS ( SELECT  *
            FROM    sys.objects
            WHERE   type = 'TR'
                    AND name = 'Insert_WithdrawalCodes' ) 
BEGIN
    EXEC ('CREATE TRIGGER Insert_WithdrawalCodes ON ...');
END;

由于上面的其他答案没有提到重要的一点,我写了这个答案:

  • 当我们想在sys.objectstable中查找触发器或其他对象时,最好准确检查(使用schema或object_id等) in where 子句避免同名无效结果。 考虑另一个具有相同名称的触发器何时已存在于另一个模式中...... 因此,因为 sys.object table 包含一个 schema_id 列,所以除了 nametype 列之外,我们还可以使用它来更准确地查询,正如我提供的那样下面的示例。

  • 正如 Microsoft 文档在 "Trigger Limitations" 下提到的 here

CREATE TRIGGER must be the first statement in the batch and can apply to only one table.

因此我们使用EXECUTE来克服这个限制:

IF NOT EXISTS (select * from sys.objects where schema_id=SCHEMA_ID('dbo') AND type='TR' and name='Insert_WithdrawalCodes')
BEGIN
   EXECUTE ('CREATE TRIGGER [Insert_WithdrawalCodes] ON [dbo].[PupilWithdrawalReason]
   AFTER INSERT
   AS 
   BEGIN
      SET NOCOUNT ON;
      ...
   END');
END