2016-02-13 53 views
0

我使用SQL服務器2012年我寫了這樣一個觸發器:觸發器(UPDATE後)導致錯誤?

ALTER TRIGGER [dbo].[ModValue] 
    ON [dbo].[Table1] 
    AFTER UPDATE 
AS 
BEGIN 
    SET NOCOUNT ON; 
    declare @ocid bigint 
    declare @ncid bigint,@pid bigint 

    set @ocid=(select CategoryId from deleted) 
    select @ncid=CategoryId,@pid=Id from inserted 

    if(@ocid<>@ncid) 
    begin 
    delete from [Table2] where [email protected] 
    delete from [Table3] where [email protected] 
    delete from [Table4] where [email protected] 
    end 
END 

當我想更新我的表(表1)我得到這個錯誤:

Msg 512, Level 16, State 1, Procedure ModValue, Line 15
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression. The statement has been terminated.

更新查詢:

update Table1 
set sizing = 0 
where categoryid = 238 

這個腳本有什麼問題?

+5

你的觸發器有** MAJOR **缺陷,因爲你認爲它會被稱爲每行**一次** - 這是**不是**的情況。它會在每個語句**中觸發一次**。如果你的'UPDATE'語句更新了25行,你將會觸發**觸發**一次**,但是'Deleted'和'Inserted'僞表每個將包含25行。您的代碼在這25行中選擇哪一個? 'set @ ocid =(從刪除中選擇CategoryId)' - 這是非確定性的,你將得到**一個任意的行**,你將**忽略所有其他行**。你需要重寫你的觸發器來考慮這個問題! –

+0

謝謝@marc_s。那是我的答案。 – Mashtani

回答

1

我認爲有以下線的問題是:

set @ocid=(select CategoryId from deleted) 

SET命令期望從SELECT聲明至多1行。 deleted表可能包含多於1行,因爲觸發器會在batch級觸發,而不是record級。

3

DELETEDINSERTED表可能包含多行。

  • DELETED - 包含了之前存在的修改(舊)
  • INSERTED數據 - 修改數據(新)。

所以,你必須找出CategoryID改爲:

... 
from 
    Inserted new 
inner join 
    Deleted old on old.id = new.id 
where 
    new.CategoryID <> old.CategoryID 

做的東西,同時牢記可能有很多行,例如:

delete from [Table2] t2 
where exists (select 1 
       from Inserted new 
       inner join Deleted old on old.id = new.id 
       where new.CategoryID <> old.CategoryID 
       and t2.ProductId = d.ProductID) 

請注意,ProductID也可以通過UPDATE聲明進行更改。