為什麼 UPDATE FROM 失敗並且 MERGE 在帶有 INSTEAD OF 觸發器的視圖上工作?
有時為了重構,我使用視圖來抽象更改並使用
INSTEAD OF
觸發器來模仿以前的功能。我過去遇到過錯誤 414(或 415)
UPDATE 是不允許的,因為語句更新了視圖“%.*ls”,它參與了一個連接並且有一個 INSTEAD OF UPDATE 觸發器。
我可以將其重寫
UPDATE FROM
為一個MERGE
語句並且有效。但為什麼?我找到了這些參考資料,但沒有一個回答原因。
https://sqlserverfast.com/blog/hugo/2008/03/lets-deprecate-update-from/
我的理解是這是不允許的,因為
UPDATE...FROM
由於向後兼容性而保持了一些古怪的行為。當視圖具有而不是觸發器時,使這些工作相同是很困難的,也許是不可能的。
MERGE
有幾個弱點,但它確實具有定義明確且健全的更新語義。這方面的主要範例是
MERGE
防止模糊更新——目標行在邏輯上被 SQL 規範多次更改。如果模式中沒有任何東西絕對保證不能多次修改目標行,則MERGE
計劃引入操作員在執行時檢查此條件,並在遇到時引發錯誤。這使得使用而不是觸發器
MERGE
在目標上實現連接表更容易/完全可能。當
UPDATE...FROM
目標表被多次引用時,語法也有奇怪的綁定行為(再次維護以避免破壞舊程式碼),有時通過別名,有時不。與您的問題沒有直接關係,但有一個文件中描述的帶有 CTE 的邊緣案例範例:
當公用表表達式 (CTE) 是 UPDATE 語句的目標時,語句中對 CTE 的所有引用都必須匹配。例如,如果在 FROM 子句中為 CTE 分配了別名,則別名必須用於對 CTE 的所有其他引用。需要明確的 CTE 引用,因為 CTE 沒有對象 ID,SQL Server 使用它來辨識對象與其別名之間的隱式關係。如果沒有這種關係,查詢計劃可能會產生意外的連接行為和意外的查詢結果。
綜上所述,僅僅因為它可以工作
MERGE
並不意味著沒有潛伏的錯誤。有關半相關範例,請參閱MERGE into a view with INSTEAD OF triggers。在復雜特徵組合的邊緣努力是找到邊緣情況錯誤的好方法。