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

資料庫觸發器差異解析:DB2 與 SQL Server 語法與行為對照

     編輯:關於SqlServer

核心差異速覽

維度DB2SQL Server
觸發時機關鍵字BEFORE / AFTER / INSTEAD OFAFTER / INSTEAD OF (無 BEFORE)
新舊資料引用REFERENCING NEW AS N_ROW (可自訂別名)inserted / deleted 虛擬表 (固定名稱)
行級觸發FOR EACH ROW MODE DB2SQL 明確指定隱含行級 (觸發器內處理多列)
變數宣告DECLARE var TYPE; (無前綴)DECLARE @var TYPE; (@ 前綴)
賦值語法SET var = value; 或 SELECT ... INTO var FROM ...SET @var = value; / SELECT @var = col FROM ...
異常中止SIGNAL SQLSTATE '80000' ('msg')THROW 50000, 'msg', 1; / RAISERROR
觸發後預設行為無錯誤 → 隱含提交 DML無錯誤 → 不隱含執行原 DML,需在觸發器內重寫 INSERT/UPDATE/DELETE

對照範例:防止重複代碼插入

DB2 版本

CREATE TRIGGER EAS.trName 
NO CASCADE BEFORE INSERT ON EAS.T_User
REFERENCING NEW AS N_ROW
FOR EACH ROW MODE DB2SQL
BEGIN ATOMIC
  DECLARE U_xtfidemp1 VARCHAR(36);
  DECLARE u_xtempcode1 VARCHAR(20);
  DECLARE u_xtempcodeCount INT;
  DECLARE U_xtfidempCount INT;
  DECLARE u_id1 INT;

  SET U_xtfidemp1 = N_ROW.U_xtfidemp;
  SET u_xtempcode1 = N_ROW.u_xtempcode;
  SET u_id1 = N_ROW.u_id;

  SET u_xtempcodeCount = (SELECT COUNT(u_xtempcode) FROM EAS.T_User 
                          WHERE u_xtempcode IS NOT NULL AND u_xtempcode = u_xtempcode1 AND u_id <> u_id1);
  SET U_xtfidempCount = (SELECT COUNT(U_xtfidemp) FROM EAS.T_User 
                         WHERE U_xtfidemp IS NOT NULL AND U_xtfidemp = U_xtfidemp1 AND u_id <> u_id1);

  IF u_xtempcodeCount > 0 OR U_xtfidempCount > 0 THEN
    SIGNAL SQLSTATE '80000' ('EAS.T_User Exceeds u_xtempcode,U_xtfidemp 重複');
  END IF;
END

SQL Server 版本

CREATE TRIGGER EAS.trName 
ON EAS.T_User
FOR INSERT  -- SQL Server 無 BEFORE,用 AFTER (預設) 或 INSTEAD OF
AS
BEGIN
  DECLARE @U_xtfidemp1 VARCHAR(36);
  DECLARE @u_xtempcode1 VARCHAR(20);
  DECLARE @u_xtempcodeCount INT;
  DECLARE @U_xtfidempCount INT;
  DECLARE @u_id1 INT;

  -- 從 inserted 虛擬表取值 (支援多列)
  SELECT @U_xtfidemp1 = U_xtfidemp, @u_xtempcode1 = u_xtempcode, @u_id1 = u_id FROM inserted;

  SET @u_xtempcodeCount = (SELECT COUNT(u_xtempcode) FROM EAS.T_User 
                           WHERE u_xtempcode IS NOT NULL AND u_xtempcode = @u_xtempcode1 AND u_id <> @u_id1);
  SET @U_xtfidempCount = (SELECT COUNT(U_xtfidemp) FROM EAS.T_User 
                          WHERE U_xtfidemp IS NOT NULL AND U_xtfidemp = @U_xtfidemp1 AND u_id <> @u_id1);

  IF @u_xtempcodeCount > 0 OR @U_xtfidempCount > 0 BEGIN
    -- INSTEAD OF 觸發器中需自行決定是否執行原 INSERT
    -- AFTER 觸發器中拋錯誤會回滾原 INSERT
    THROW 50000, 'EAS.T_User Exceeds u_xtempcode,U_xtfidemp 重複', 1;
  END
END

關鍵行為差異深度解析

1. BEFORE vs AFTER/INSTEAD OF

  • DB2 BEFORE 觸發器在 DML 執行前執行,可修改 N_ROW 內容影響寫入值。
  • SQL Server 無 BEFORE。AFTER 在 DML 完成後執行 (同交易內);INSTEAD OF 取代原 DML,觸發器必須自行執行 INSERT/UPDATE/DELETE,否略原操作不會發生。

2. 行級處理與多列 inserted

  • DB2 FOR EACH ROW 明確逐列觸發,N_ROW 為單列記錄。
  • SQL Server 觸發器每陳述式觸發一次,inserted/deleted 含所有影響列。需用 JOIN inserted 或游標逐列處理,或接受集合式邏輯 (如上例 SELECT ... FROM inserted 只取第一列,實務應處理多列)。

3. 異常處理與回滾

  • DB2 SIGNAL 拋出自定義 SQLSTATE,觸發器失敗導致原 DML 回滾。
  • SQL Server THROW / RAISERROR 拋錯,AFTER 觸發器中會回滾原 DML;INSTEAD OF 中拋錯僅回滾觸發器內交易,原 DML 已被取代不存在。

遷移檢查清單

  1. 將 BEFORE INSERT/UPDATE → INSTEAD OF INSERT/UPDATE (需重寫 DML) 或 AFTER (若僅驗證)。
  2. 將 REFERENCING NEW AS X → inserted / deleted。
  3. 變數加 @ 前綴。
  4. SET var = val → SET @var = val;SELECT ... INTO var → SELECT @var = col FROM ...。
  5. SIGNAL → THROW (SQL 2012+) 或 RAISERROR。
  6. 檢查多列 inserted 處理邏輯 (集合式 vs 逐列)。
  7. 驗證 INSTEAD OF 觸發器中是否正確重寫原 DML。

結語

DB2 與 SQL Server 觸發器在觸發時機、行級/陳述式級、虛擬表存取、異常語法、預設 DML 行為五大維度存在本質差異。遷移時不可逐行翻譯,必須理解語意並重寫邏輯。建議將複雜業務規則移至預存程序/應用層,觸發器僅作最後防線 (稽核、同步、不可由應用層保證的約束)。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved