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