2016-02-02 29 views
1

我想創建修改現有觸發器的過程。觸發器負責阻止使用特定ID更新的行。我想類似的東西:修改現有觸發器的步驟

CREATE PROCEDURE Change_trigger 
    @List_of_ids varchar(8000) 
AS 
ALTER TRIGGER blocks 
ON ttt 
INSTEAD OF update 
AS 
BEGIN 
    If (SELECT Id_ttt FROM inserted) IN (@List_of_ids) 
     BEGIN 
      raiserror('You cannot modify this record.', 12, 1) 
      RETURN 
     END 

    UPDATE ttt 
    SET 
    field1 = INSERTED.field1 
    FROM INSERTED 
    WHERE INSERTED.Id_ttt = ttt.Id_ttt 
END 

參數@List_of_ids會是這樣:2,3,4,5,9,52。但是當我嘗試創建此過程時出現錯誤:

Msg 156, Level 15, State 1, Procedure Change_trigger, Line 4
Incorrect syntax near the keyword 'TRIGGER'.

觸發器已創建。

+1

而不是不斷修改觸發器,爲什麼不只是一個包含觸發器然後引用的禁止ID的表?然後程序可以照顧填充這張表 - 如果這個程序是需要的話。順便說一下,SQL Server內置了*設計*來處理多個值(表值參數,XML)。 'varchar'不是其中之一。 –

+1

此外,您的觸發器已損壞。 「IN」運算符在其左側需要一個標量值。當'inserted'包含*多行*(因爲它很容易)時,觸發器會產生一個錯誤。 (當然,單個更新可能會影響塊列表中的某些*行,以及某些*行不是這樣的行。您想如何處理這種情況?目前,所有這些更新都會被拒絕,但那是你想要的*還是僅僅是你已經建立了這個觸發器的意外?) –

+0

@Damien_The_Unbeliever,謝謝你的評論。那麼如何處理一個查詢中的多行更新?當我想保持這樣的觸發器時,要阻止特定的ID?你還提到其他表格在那裏存儲禁止的ID。這真有趣。但我需要程序,因爲這個阻塞ID將會改變 – XardasLord

回答

1

這是我會寫,一旦觸發。

ALTER TRIGGER blocks 
ON ttt 
INSTEAD OF update 
AS 
BEGIN 
    SET NOCOUNT ON 

    UPDATE t 
    SET 
    field1 = i.field1 
    FROM INSERTED i 
      inner join 
     ttt t 
      on i.Id_ttt = t.Id_ttt 
      left join 
     ttt_blocked on tb 
      on 
       i.Id_ttt = tb.Id_ttt 
    WHERE 
     tb.Id_ttt is null 
END 

注意,這觸發不再拋出錯誤阻止更新,但它確實允許一個混合版本(某些行受阻,一些行不)發生。有沒有乾淨的方式來提出錯誤,同時仍然部分應用觸發器中的更新

然後我有一個表(如上文引用):

CREATE TABLE ttt_blocked (
    Id_ttt int not null, 
    constraint PK_ttt_blocked PRIMARY KEY (Id_ttt) 
) 

然後,如果有必要,我會創建一個過程來維護這個而不是不斷變化的數據庫模式:

CREATE PROCEDURE Change_blocking 
    @BlockedIDs xml 
AS 
    --Better option would be table-valued parameters 
    --but I've chosen to do XML today 

    --We expect the XML to be of the form 
    --<blocks> 
    -- <id>10</id> 
    -- <id>15</id> 
    --</blocks> 

    MERGE INTO ttt_blocked t 
    USING (select x.id.value('text()[1]','int') 
      from @BlockedIDs.nodes('/blocks/id') x(id)) s(Id_ttt) 
    ON 
     t.Id_ttt = s.Id_ttt 
    WHEN NOT MATCHED THEN INSERT (Id_ttt) VALUES (s.Id_ttt) 
    WHEN NOT MATCHED BY SOURCE THEN DELETE; 

正如我也影射上面,我通常建議Table-Valued Parameters而不是XML(和它們中的領先varchar因爲他們是設計來保存多個值),但它會增加更多的代碼給這個答案。

+0

而不是創建過程,我可以直接從我的應用程序權限添加/刪除行ttt_blocked表?我不需要程序 – XardasLord

+1

@ XardasLord - 是的,這就是爲什麼我在回答「必要時」或在評論中「如果程序是需要的」。 –

+0

我有一個問題,是否有任何方式來保持這樣的條件:'如果(SELECT Id_ttt FROM插入)IN(SELECT Id_ttt FROM ttt_blocked)'並顯示記錄被阻止時的錯誤消息?但我的意思是一個更新幾行的查詢。通過「插入」或某些東西循環? – XardasLord

1

試試這個..

CREATE PROCEDURE Change_trigger 
    @List_of_ids varchar(4000) 
AS 
begin 
declare @sql varchar(8000) 

set @sql =' 
ALTER TRIGGER blocks 
ON ttt 
INSTEAD OF update 
AS 
BEGIN 
    if exists (SELECT Id_ttt FROM inserted where Id_ttt IN ('[email protected]_of_ids+')) 
     BEGIN 
      raiserror(''You cannot modify this record.'', 12, 1) 
      RETURN 
     END 

    UPDATE ttt 
    SET 
    field1 = INSERTED.field1 
    FROM INSERTED 
    WHERE INSERTED.Id_ttt = ttt.Id_ttt 
END' ; 
exec (@sql); 
END 
+0

很好,程序已創建。但是當我嘗試執行它時,我得到了這個錯誤:'Msg 102,Level 15,State 1,Procedure change,Line 40 對象「Id_ttt」'附近的語法錯誤。我用這個來執行:'EXEC Change_trigger @List_of_ids ='2,4,6'' – XardasLord

+0

SELECT Id_ttt FROM insert where Id_ttt IN(@List_of_ids)。這是正確的systax嗎? –

+1

你不能只是'IF(查詢)'。你可能在尋找'EXISTS'。此外,Xardas報告的錯誤可能是通過爲觸發器的BEGIN添加匹配的「END」來解決的。 –