首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

SQL Server 觸發器規範 INSERT/UPDATE 的 DATETIME 欄位:只保留日期部分

     編輯:MySQL 資料庫相關知識

需求:表 A 的主鍵為 (ProductID, RetailerID, Date),其中 Date 僅保留「年-月-日」,不含時分秒。應用層若直接寫入 DATETIME 完整時間,會導致主鍵衝突或語意不符。若無法控制應用端輸入,必須在資料庫層透過觸發器強制截取日期。

觸發器寫法對比:Oracle/MySQL vs SQL Server

  • Oracle / MySQL:擁有 NEW、OLD 伪表,可直接賦值 NEW.Date = TRUNC(NEW.Date),修改生效、無額外 I/O。
  • SQL Server:無 NEW/OLD,僅提供 INSERTED、DELETED 邏輯表,無法在觸發器中直接修改即將寫入的值,只能事後 UPDATE 回寫。

SQL Server 可行方案:AFTER 觸發器 + UPDATE 回寫

CREATE TRIGGER A_T ON A
FOR INSERT, UPDATE
AS
BEGIN
    UPDATE A
    SET Date = CONVERT(DATE, I.Date)  -- SQL Server 2008+ 直接用 DATE 類型
    FROM INSERTED I
    WHERE I.ID = A.ID;
END;

副作用:每次 INSERT/UPDATE 會觸發兩次寫入操作(原操作 + 觸發器 UPDATE),輸出訊息顯示 (1 行受影響) 兩次,效能與日誌量雙倍增長。

替代方案評估

方案優點缺點適用版本
AFTER 觸發器 UPDATE 回寫 相容舊版、邏輯簡單 雙倍寫入、觸發遞迴風險、需防呆 所有版本
改用 DATE 類型(SQL Server 2008+) 儲存層面原生只存日期、無觸發器開銷 需修改表結構、應用層參數型別同步調整 2008+
INSTEAD OF 觸發器 可攔截並重寫 INSERT/UPDATE 邏輯、單次寫入 需手寫完整欄位清單、維護成本高、易遺漏欄位 2000+
計算欄位 + 索引 不存冗余、查詢可用索引 無法直接做主鍵(除非 PERSISTED),主鍵仍需原始欄位 2005+
CHECK 條件約束 攔截非法資料、零額外 I/O 只能拒絕、無法自動修正(截取日期) 所有版本

最佳實踐建議

  1. 首選:修改表結構改用 DATE 類型(SQL Server 2008+),從源頭解決,零執行期開銷。
  2. 若不可改結構,評估 INSTEAD OF 觸發器 取代 AFTER,避免雙寫,但需完整列出所有欄位。
  3. 若僅需防呆,加 CHECK (Date = CONVERT(DATE, Date)) 條件約束,強制應用端自行修正。
  4. 避免長期使用 AFTER 觸發器 UPDATE 回寫,高併發下易成寫入熱點與日誌膨脹源頭。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved