SQL Server 無 BEFORE 觸發器,但 INSTEAD OF 觸發器可攔截 DML 操作並在執行前自訂邏輯,完美對應 Oracle BEFORE 語意。
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
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
| 特性 | 說明 |
|---|---|
| 攔截操作 | 原 DML 不自動執行,完全由觸發器控制是否/如何執行 |
| 虛擬表 | inserted (新值)、deleted (舊值) 同 AFTER 觸發器 |
| 可更新檢視表 | 唯一支援透過檢視表修改多張基表的機制 |
| 每表每事件一個 | 同一表同一事件 (INSERT/UPDATE/DELETE) 僅能建立一個 INSTEAD OF 觸發器 |
| 遞歸控制 | 觸發器內執行同表 DML 不會再次觸發自身 (除非啟用遞歸) |
AFTER:操作完成後執行,適合稽核、同步、通知等副作用。INSTEAD OF:操作前攔截,適合業務驗證、替代邏輯、檢視表更新。CHECK 約束 / UNIQUE 索引解決的驗證,不要用觸發器。FK CASCADE DELETE 解決的級聯,優先用 FK (宣告式、效能佳、工具支援好)。SET NOCOUNT ON 減少網路封包。THROW 保留呼叫堆疊,應用層可捕捉具體錯誤。