首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

SQL Server INSTEAD OF 觸發器實現 Oracle BEFORE 觸發器功能:插入前檢查與級聯刪除

     編輯:關於SqlServer

SQL Server 無 BEFORE 觸發器,但 INSTEAD OF 觸發器可攔截 DML 操作並在執行前自訂邏輯,完美對應 Oracle BEFORE 語意。

案例 1:插入前檢查重複,不存在才插入

CREATE TRIGGER TR_ProductCategory_PreventDuplicate
ON ProductCategory
INSTEAD OF INSERT
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @CategoryName NVARCHAR(50);
    SELECT @CategoryName = CategoryName FROM inserted;
    
    IF EXISTS (SELECT 1 FROM ProductCategory WHERE CategoryName = @CategoryName)
    BEGIN
        PRINT 'Category already exists, insert skipped.';
        -- 可選:RAISERROR / THROW 回傳錯誤給應用層
        RETURN;
    END
    
    -- 執行實際插入
    INSERT INTO ProductCategory (CategoryName, ...)
    SELECT CategoryName, ... FROM inserted;
END

案例 2:刪除主表時自動級聯刪除從表 (替代 FK CASCADE)

CREATE TRIGGER TR_OrderHeader_CascadeDelete
ON OrderHeader
INSTEAD OF DELETE
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @OrderId VARCHAR(50);
    SELECT @OrderId = OrderId FROM deleted;
    
    -- 先刪從表
    DELETE FROM OrderLine WHERE OrderId = @OrderId;
    -- 再刪主表
    DELETE FROM OrderHeader WHERE OrderId = @OrderId;
END

INSTEAD OF 關鍵特性

特性說明
攔截操作原 DML 不自動執行,完全由觸發器控制是否/如何執行
虛擬表inserted (新值)、deleted (舊值) 同 AFTER 觸發器
可更新檢視表唯一支援透過檢視表修改多張基表的機制
每表每事件一個同一表同一事件 (INSERT/UPDATE/DELETE) 僅能建立一個 INSTEAD OF 觸發器
遞歸控制觸發器內執行同表 DML 不會再次觸發自身 (除非啟用遞歸)

對比:AFTER vs INSTEAD OF

  • AFTER:操作完成後執行,適合稽核、同步、通知等副作用。
  • INSTEAD OF:操作前攔截,適合業務驗證、替代邏輯、檢視表更新。

最佳實務建議

  1. 能用 CHECK 約束 / UNIQUE 索引解決的驗證,不要用觸發器。
  2. 能用 FK CASCADE DELETE 解決的級聯,優先用 FK (宣告式、效能佳、工具支援好)。
  3. 觸發器內禁止長時間運算/外部呼叫,會阻塞原交易鎖定資源。
  4. 使用 SET NOCOUNT ON 減少網路封包。
  5. 錯誤處理用 THROW 保留呼叫堆疊,應用層可捕捉具體錯誤。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved