2017-03-05 58 views
2

我有一個觸發器:觸發處理多個刀片

CREATE TRIGGER tgr_incheck_vlucht 
ON PassagierVoorVlucht 
AFTER INSERT, UPDATE 
AS 
BEGIN 
IF @@ROWCOUNT= 0 BEGIN RETURN END 
SET NOCOUNT ON 
BEGIN TRY 
IF EXISTS 
    (SELECT * 
    FROM inserted I 
    WHERE EXISTS(SELECT * 
        FROM PassagierVoorVlucht P inner join Vlucht V on P.vluchtnummer = V.vluchtnummer 
        WHERE I.inchecktijdstip >= vertrektijdstip)) 
BEGIN 
RAISERROR('Inchecktijdstip moet voor de aankomsttijdliggen', 16,1) 
END 
END TRY 
BEGIN CATCH 
    IF @@TRANCOUNT > 0 BEGIN ROLLBACK TRANSACTION END 
    DECLARE @ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE(), 
      @errorSeverity INT = ERROR_SEVERITY(), 
      @errorState INT = ERROR_STATE() 
    RAISERROR (@ErrorMessage, @errorSeverity, @errorState) 
END CATCH 
END 

現在我已經寫了一些測試語句:

INSERT INTO PassagierVoorVlucht 
VALUES(850, 5316, 1, '2002-01-01 13:37:00.000', 21), 
(1002, 5316, 1, '2004-01-01 13:37:00.000', 21), 
(1601, 5316, 1, '2004-05-01 13:37:00.000', 21), 
(1602, 5316, 1, '2004-05-01 13:37:00.000', 21) 

觸發當時的工作只有一個插入的行不是爲整個街區。我如何編寫可以處理多個插入的觸發器?

+0

你是什麼意思「處理多個插入」?你想讓錯誤提出四次嗎? –

+0

不,前兩個插入值行是好的,必須插入,最後兩個插入值的行都是假的,必須回退。但現在它沒有插入任何東西。我希望你能理解它。 – Yakalent

+1

好吧,你正在檢查是否有*行違反了你的商業邏輯,並且回滾了所有的東西。你可能會考慮一個'INSTEAD OF'插入觸發器,你可以在其中插入*不違反業務邏輯的行。 –

回答

1

答案是你不能...基本上,觸發器被解僱爲每個插入,而不是一批代碼。這就是爲什麼它被稱爲觸發器或響應。另外,如果你的表有一個插入標識列,觸發器不會阻止行間的差距,因爲它們的功能就像序列一樣:在行級激活,並且在語句完成後(除非INSTEAD OF)。

解釋觸發也許有幫助的是從MSDN以下:

CREATE TRIGGER (Transact-SQL)

雖然TRUNCATE TABLE語句實際上是DELETE語句,因爲操作不不激活觸發器記錄單個行刪除。但是,只有那些有權執行TRUNCATE TABLE語句的用戶需要關注無意中繞過這種DELETE觸發器。

注意關於單個行刪除的部分以及關於範圍的一點。也許更瞭解你的要求可能會使解決方案變得清晰。

現在,您可以使用INSTEAD OF觸發器在嘗試執行代碼之前觸發,但這可能不會成爲解決方案,除非您有一些臨時表設置或類似的功能。而不是替換整個DML或DDL語句。

  • 如果您希望保護數據的完整性,請考慮使用存儲的或預先規劃的過程。

  • 如果這是不可接受的或不切實際的,其他的約束如引用鍵或甚至暫存表(取決於對數據的及時性的需要)可以稍後導入可以是選項。