【发布时间】:2015-03-30 11:36:20
【问题描述】:
我有以下原始触发器,对我来说效果很好:http://pastebin.com/raw.php?i=mbsrYvJq
我最近发现,当表(放置此触发器)接收批量更新时,这不起作用。我收到以下错误:
消息 512,级别 16,状态 1,过程 IC_ProductUpdate,第 7 行
子查询返回超过 1 个值。这是不允许的,当 子查询遵循 =、!=、、>= 或当子查询用作 一种表达。该语句已终止。
所以我做了一些挖掘,发现了这个答案:https://stackoverflow.com/a/17059565/2332336
所以,我更新了我的触发器以使用光标,它现在看起来像这样:
ALTER TRIGGER [dbo].[IC_ProductUpdate]
ON [dbo].[StockItem]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON
SET XACT_ABORT ON
DECLARE @StockItemID INT
DECLARE cur CURSOR FORWARD_ONLY READ_ONLY LOCAL FOR
SELECT StockItemID
FROM INSERTED
OPEN cur
FETCH NEXT FROM cur INTO @StockItemID
WHILE @@FETCH_STATUS = 0 BEGIN
-- Proceed If This Product Is Syncable
IF (dbo.IC_CanSyncProduct(@StockItemID) = 1)
BEGIN
-- Check If Product Was Synced
IF ((SELECT COUNT(*) FROM IC_ProductCreateQueue WITH (NOLOCK) WHERE StockItemID = @StockItemID) > 0)
BEGIN
-- Check If Any Important Columns Was Updated
IF (UPDATE(Weight) OR UPDATE(SpareNumber1))
BEGIN
-- Check If There Is A [ProductUpdate] Queue Entry Already Exist For This Product
IF ((SELECT COUNT(*) FROM IC_ProductUpdateQueue WITH (NOLOCK) WHERE StockItemID = @StockItemID) > 0)
BEGIN
-- Reset [ProductUpdate] Queue Entry
UPDATE IC_ProductUpdateQueue SET Synced = 0
WHERE StockItemID = @StockItemID
END
ELSE
BEGIN
-- Insert [ProductUpdate] Queue Entry
INSERT INTO IC_ProductUpdateQueue (StockItemID, Synced) VALUES
(@StockItemID, 0)
END
END
END
ELSE
BEGIN
-- Insert [ProductCreate] Queue Entry
INSERT INTO IC_ProductCreateQueue (StockItemID, Synced) VALUES
(@StockItemID, 0);
-- Insert [ProductUpdate] Queue Entry
INSERT INTO IC_ProductUpdateQueue (StockItemID, Synced) VALUES
(@StockItemID, 0);
END
END
FETCH NEXT FROM cur INTO @StockItemID
END
CLOSE cur
DEALLOCATE cur
END
当我尝试更新触发器 (F5) 时,它似乎不起作用并给我这个错误:
消息 207,级别 16,状态 1,过程 IC_ProductUpdate,第 12 行
列名“StockItemID”无效。
知道为什么会这样吗?有没有更好的方法来更新我的触发器以处理同时更新的多行?
【问题讨论】:
-
天哪.....请不要在触发器中使用游标!这就是您可以为性能做的最差!将其重写为 基于集合的 操作 - 否则会破坏所有数据库性能。 .....触发器应该总是非常小,快速,精益 - 而光标则不是......
-
嗨,marc_s,感谢您的提示。您能否提供一个示例或链接来指导如何进行基于集合的操作?
-
您在此触发器中进行了太多处理。触发器在导致它触发的语句的上下文中执行,并且应该非常精简、快速、灵活。不要不要在触发器中进行大量处理!相反:在触发器中,只需将需要执行的操作记入“命令”表;然后创建一个单独的进程(例如,一个 T-SQL 计划作业)来检查该“命令”表,例如每小时一次,如果需要,进行繁重的处理。这样,您的触发器变得 (a) 更易于编写,并且 (b) 对您的数据库系统的负担要小得多
标签: sql-server tsql triggers