Sql 是否需要在每个触发器中将XACT_ABORT设置为ON?
这是一个旧的SQL Server 2008 Express数据库(实际上有五个),我刚刚迁移到SQL Server 2019 Express。一切似乎都很顺利,直到我的船员进来,我们到处都有错误。事实证明,触发器中有Sql 是否需要在每个触发器中将XACT_ABORT设置为ON?,sql,sql-server,error-handling,triggers,Sql,Sql Server,Error Handling,Triggers,这是一个旧的SQL Server 2008 Express数据库(实际上有五个),我刚刚迁移到SQL Server 2019 Express。一切似乎都很顺利,直到我的船员进来,我们到处都有错误。事实证明,触发器中有RAISEERROR,即使我的兼容性似乎设置为2008(100),我们仍然会收到错误。所以我升级到了THROW。现在一切看起来都很好,但由于我不是DBA,我担心我的升级会损坏一些数据或留下孤儿。以下是其中一个触发器的示例: USE [toddAPB] GO /****** Objec
RAISEERROR
,即使我的兼容性似乎设置为2008(100),我们仍然会收到错误。所以我升级到了THROW
。现在一切看起来都很好,但由于我不是DBA,我担心我的升级会损坏一些数据或留下孤儿。以下是其中一个触发器的示例:
USE [toddAPB]
GO
/****** Object: Trigger [dbo].[T_tSaleLineItem_ITrig] Script Date: 5/18/2021 1:32:55 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[T_tSaleLineItem_ITrig] ON [dbo].[tSaleLineItem] FOR INSERT AS
SET NOCOUNT ON
/* * PREVENT INSERTS IF NO MATCHING KEY IN 'tProduct' */
IF (SELECT COUNT(*) FROM inserted) !=
(SELECT COUNT(*) FROM tProduct, inserted WHERE (tProduct.RecNumP = inserted.RecNumP))
BEGIN
;THROW 44447, 'The record can''t be added or changed. Referential integrity rules require a related record in table ''tProduct''.',1;
ROLLBACK TRANSACTION
END
/* * PREVENT INSERTS IF NO MATCHING KEY IN 'tSale' */
IF (SELECT COUNT(*) FROM inserted) !=
(SELECT COUNT(*) FROM tSale, inserted WHERE (tSale.RecNumS = inserted.RecNumS))
BEGIN
;THROW 44447, 'The record can''t be added or changed. Referential integrity rules require a related record in table ''tSale''.',1;
ROLLBACK TRANSACTION
END
我是否需要在每个触发器(数百个)上启用
SET XACT_ABORT
?我应该吗?每次抛出后是否仍需要回滚事务
在我调整到抛出之前,我得到了“语法错误接近44447”的错误。这条线以前看起来更像这样:
RAISERROR 44447 'The record can''t be added or changed. Referential integrity rules require a related record in table ''tProduct''.'
谢谢你的帮助。你真的应该用外键约束来解决这个问题(谢谢Charlieface),但是如果这不实用,请继续阅读
是触发器的默认值
OFF是T-SQL语句中的默认设置,而ON是触发器中的默认设置
您还应该使用正确的联接,而不是隐式联接。我已经用正确终止的语句说明了如何编写触发器
ALTER TRIGGER [dbo].[T_tSaleLineItem_ITrig]
ON [dbo].[tSaleLineItem]
FOR INSERT AS
BEGIN
SET NOCOUNT ON;
/* PREVENT INSERTS IF NO MATCHING KEY IN 'tProduct' */
IF (SELECT COUNT(*) FROM inserted) != (SELECT COUNT(*) FROM tProduct P INNER JOIN inserted I ON P.RecNumP = I.RecNumP)
BEGIN
THROW 44447, 'The record can''t be added or changed. Referential integrity rules require a related record in table ''tProduct''.', 1;
END;
/* PREVENT INSERTS IF NO MATCHING KEY IN 'tSale' */
IF (SELECT COUNT(*) FROM inserted) != (SELECT COUNT(*) FROM tSale S INNER JOIN inserted I ON S.RecNumS = I.RecNumS)
BEGIN
THROW 44447, 'The record can''t be added or changed. Referential integrity rules require a related record in table ''tSale''.', 1;
END;
END;
当然,您可以继续使用,但自您最初编写它以来,语法似乎已经发生了变化,因此您必须纠正这一点。由于您无论如何都必须修改它们,因此移动到似乎是合适的
我觉得你的完整性检查很有趣,我会写如下由于我如何处理逻辑,但我不认为它更好
IF EXISTS (
SELECT 1
FROM Inserted I
WHERE NOT EXISTS (SELECT 1 FROM tProduct P WHERE P.RecNumP = I.RecNumP)
)
实际上,您应该使用外键约束来解决这个问题(谢谢Charlieface),但是如果这不实用,请继续阅读
是触发器的默认值
OFF是T-SQL语句中的默认设置,而ON是触发器中的默认设置
您还应该使用正确的联接,而不是隐式联接。我已经用正确终止的语句说明了如何编写触发器
ALTER TRIGGER [dbo].[T_tSaleLineItem_ITrig]
ON [dbo].[tSaleLineItem]
FOR INSERT AS
BEGIN
SET NOCOUNT ON;
/* PREVENT INSERTS IF NO MATCHING KEY IN 'tProduct' */
IF (SELECT COUNT(*) FROM inserted) != (SELECT COUNT(*) FROM tProduct P INNER JOIN inserted I ON P.RecNumP = I.RecNumP)
BEGIN
THROW 44447, 'The record can''t be added or changed. Referential integrity rules require a related record in table ''tProduct''.', 1;
END;
/* PREVENT INSERTS IF NO MATCHING KEY IN 'tSale' */
IF (SELECT COUNT(*) FROM inserted) != (SELECT COUNT(*) FROM tSale S INNER JOIN inserted I ON S.RecNumS = I.RecNumS)
BEGIN
THROW 44447, 'The record can''t be added or changed. Referential integrity rules require a related record in table ''tSale''.', 1;
END;
END;
当然,您可以继续使用,但自您最初编写它以来,语法似乎已经发生了变化,因此您必须纠正这一点。由于您无论如何都必须修改它们,因此移动到似乎是合适的
我觉得你的完整性检查很有趣,我会写如下由于我如何处理逻辑,但我不认为它更好
IF EXISTS (
SELECT 1
FROM Inserted I
WHERE NOT EXISTS (SELECT 1 FROM tProduct P WHERE P.RecNumP = I.RecNumP)
)
将XACT_ABORT设置为ON
是触发器的默认设置。这与从raiserror
更改为throw
有什么关系?默认情况下,throw
也会回滚。此外,如果您使用正确终止您的语句
您不需要在您的抛出之前添加一个(但由于存在错误,SSMS仍会将其显示为红色)。你得到的实际错误是什么raiserror
仍然受支持?@DauntlessRob我相信这个问题已经解决了。您可以将xact_abort配置为在服务器级别打开,如果您为每个过程都设置它,这将更有意义。我建议实施适当的外键约束并完全转储此触发器。@Stu谢谢!我不知道。刚打开它。。。等待尖叫声…将XACT_ABORT设置为ON
是触发器的默认设置。这与从raiserror
更改为throw
有什么关系?默认情况下,throw
也会回滚。此外,如果您使用正确终止您的语句
您不需要在您的抛出之前添加一个(但由于存在错误,SSMS仍会将其显示为红色)。你得到的实际错误是什么raiserror
仍然受支持?@DauntlessRob我相信这个问题已经解决了。您可以将xact_abort配置为在服务器级别打开,如果您为每个过程都设置它,这将更有意义。我建议实施适当的外键约束并完全转储此触发器。@Stu谢谢!我不知道。刚打开它。。。等待尖叫声…非常感谢!这是一个很大的帮助。(我之前的几位前辈都设置了这一切,我没有DBA方面的培训。)显然,无论如何,您都会使用FK而不是触发器来进行完整性检查。非常感谢!这是一个很大的帮助。(在我之前有几位前辈设置了所有这些,我没有DBA方面的培训。)显然,无论如何,您都会使用FK而不是触发器来进行完整性检查