这个问题非常类似于SQL Server 2005: T-SQL to temporary disable a trigger
但是,我不想禁用所有触发器,甚至不想禁用一批命令,而只想禁用一个 INSERT。
我必须处理一个商店系统,原作者将一些应用程序逻辑放入触发器中(坏主意!)。只要您不尝试以不同于原始“管理前端”的其他方式插入数据,该应用程序逻辑就可以正常工作。我的工作是编写一个“从暂存系统导入”工具,因此我已准备好所有数据。当我尝试插入它时,触发器会用生成的代码覆盖现有的产品代码(不是 IDENTITY 数字 ID!)。为了生成代码,它使用插入到另一个表的自动生成的 ID,因此我什至无法使用 @@IDENTITY 来查找我刚刚插入的列并使用实际产品代码更新插入的行。
我可以采取任何方式来避免极其尴尬的代码(在产品名称中插入一些随机字符,然后尝试找到包含随机字符的行以更新它)。
那么:有没有办法为一个INSERT 禁用触发器(甚至只有一个)?
您可能会发现这很有帮助:
但是您还可能面临另一个问题。如果我正确理解你所处的情况,你的系统默认会自动插入产品代码(通过生成值)。现在您需要插入一个由某个登台系统创建的产品,并且对于该产品,其产品代码是由登台系统创建的,您希望将其手动插入到实时系统中。
如果你真的必须这样做,你需要确保你的实时应用程序在未来生成的代码不会与你手动插入的代码冲突——我认为它们必须是唯一的。
其他方法是允许系统生成新代码并在需要时覆盖任何相应的数据。
您可以使用以下命令禁用表上的触发器:
ALTER TABLE MyTable DISABLE TRIGGER ALL
但这会为所有会话都这样做,而不仅仅是你当前的连接。这显然是一件非常糟糕的事情:-)
最好的方法是改变触发器本身,以便它决定是否需要运行,无论是在表上使用“插入类型”标志还是在您已经存储某种类型的情况下使用其他方式。
除了禁用触发器之外,您还可以不更改触发器的行为。向相关表中添加一个新的可为空的列,称为“insertedFromImport”。
在触发器中更改代码,以便触发器的违规位仅在“insertedFromImport”为空的行上运行。当您插入记录时,将“insertedFromImport”设置为非空值。
禁用触发器、插入、提交。
SET IDENTITY_INSERT Test ON
GO
BEGIN TRAN
DISABLE TRIGGER trg_Test ON Test
INSERT INTO Test (MyId, MyField)
VALUES (999, 'foo')
ENABLE TRIGGER trg_Test ON Test
COMMIT TRAN
SET IDENTITY_INSERT Test OFF
GO
您能否检查 SUSER_SNAME() 并仅在管理前端的上下文中运行?
我看到很多事情可能会造成问题。首先更改触发器以考虑多条记录导入。这可能会解决您的问题。不要关闭触发器,因为它对每个人都关闭,而不仅仅是你。如果您必须在执行此操作之前将数据库置于单用户用户模式,并在下班时间执行任务。
接下来,在任何情况下都不要使用@@identity 来获取刚刚插入的值!请改用 scope_identity。如果表上的触发器也对其他具有身份字段的表执行插入操作,@@identity 将返回错误的值。如果您现在正在通过您的系统使用@@identity(因为我们知道您的系统有触发器),您绝对的首要任务必须是立即在您的代码中查找和更改@@identity 的所有实例。如果不这样做,您可能会遇到严重的数据完整性问题。这是一个“停止所有工作直到修复”的问题。
至于获取刚刚插入的信息,请考虑创建一个 batchid 作为插入的一部分,然后向表中添加一个名为 batchid 的列(可以为空,因此不会影响其他插入)。然后你可以通过batchid回调你插入的内容。
如果使用 BULK INSERT 插入,则可以仅针对插入禁用触发器。
我很确定批量插入将需要文件系统上的数据文件才能导入,因此您不能只使用 T-SQL。
要使用 BULK INSERT,您需要 INSERT 和 ADMINISTRATOR BULK OPERATION 权限。如果禁用触发器或约束,您还需要 ALTER TABLE 权限。
如果您使用的是 Windows 身份验证,则您的 Windows 用户将需要从该文件获得读取权限。如果使用混合模式身份验证,则 SQl Server 服务帐户需要从文件中读取访问权限。
使用 BULK IMPORT 导入时,默认情况下禁用触发器。