需求:A 表、B 表數據變化時,自動在 C 表中體現。提問者希望單個觸發器監聽兩表變化。
SQL Server 觸發器本質:
ON TableName)
-- A 表觸發器
CREATE TRIGGER tr_A_SyncC ON A
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
SET NOCOUNT ON;
-- 邏輯:根據 inserted/deleted 更新 C 表
MERGE C AS target
USING (SELECT key, value FROM inserted) AS source
ON target.key = source.key
WHEN MATCHED THEN UPDATE SET target.value = source.value
WHEN NOT MATCHED THEN INSERT (key, value) VALUES (source.key, source.value);
-- DELETE 需額外處理 deleted 表
END;
-- B 表觸發器(邏輯類似)
CREATE TRIGGER tr_B_SyncC ON B
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
-- 同步邏輯
END;
利用 MERGE 簡化增刪改邏輯:
CREATE TRIGGER tr_A_SyncC ON A
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
SET NOCOUNT ON;
-- 同步 INSERT/UPDATE
MERGE C WITH (HOLDLOCK) AS target
USING (
SELECT id, col1, col2, 'A' AS src FROM inserted
UNION ALL
SELECT id, col1, col2, 'A' FROM deleted WHERE NOT EXISTS (SELECT 1 FROM inserted WHERE inserted.id = deleted.id)
) AS source ON target.id = source.id AND target.src = source.src
WHEN MATCHED AND EXISTS (SELECT 1 FROM inserted WHERE inserted.id = source.id)
THEN UPDATE SET target.col1 = source.col1, target.col2 = source.col2
WHEN NOT MATCHED BY TARGET AND EXISTS (SELECT 1 FROM inserted WHERE inserted.id = source.id)
THEN INSERT (id, col1, col2, src) VALUES (source.id, source.col1, source.col2, source.src)
WHEN MATCHED AND NOT EXISTS (SELECT 1 FROM inserted WHERE inserted.id = source.id)
THEN DELETE;
END;
| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| 分表觸發器 | 原生、實時、無額外組件 | 維護多個觸發器、死鎖風險 | 低延遲、簡單邏輯 |
| CDC (Change Data Capture) | 非侵入、完整變更歷史 | 需 Enterprise 版、延遲秒級 | 審計、異步同步 |
| Service Broker | 可靠異步、解耦 | 配置複雜、學習曲線陡 | 高併發、跨實例 |
| 應用層雙寫 | 邏輯可控、易調試 | 侵入業務代碼、分布式事務難 | 微服務、強一致性要求低 |
inserted/deleted 可能包含多行IF TRIGGER_NESTLEVEL() > 1 RETURN;TRY...CATCH 記錄日誌,不拋出中斷主操作AFTER 而非 INSTEAD OFSQL Server 觸發器天然綁定單表,無法實現「單觸發器監聽多表」。正確做法是在 A、B 表上各建一個觸發器,內部邏輯更新 C 表。若同步邏輯複雜或涉及高併發,建議評估 CDC、Service Broker 或應用層方案。觸發器雖強大,但屬於「隱式邏輯」,濫用會導致維護噩夢,務必遵循「簡單、單一職責、可觀測」原則。