Sql-Server

為什麼 UPDATE FROM 失敗並且 MERGE 在帶有 INSTEAD OF 觸發器的視圖上工作?

  • January 28, 2022

有時為了重構,我使用視圖來抽象更改並使用INSTEAD OF觸發器來模仿以前的功能。

我過去遇到過錯誤 414(或 415)

UPDATE 是不允許的,因為語句更新了視圖“%.*ls”,它參與了一個連接並且有一個 INSTEAD OF UPDATE 觸發器。

我可以將其重寫UPDATE FROM為一個MERGE語句並且有效。但為什麼?

我找到了這些參考資料,但沒有一個回答原因。

https://stackoverflow.com/questions/3085036/update-is-not-allowed-because-the-statement-updates-view-table-name-which-part

https://social.msdn.microsoft.com/Forums/sqlserver/en-US/87c173b0-8f87-4aa3-b861-d40f23803a43/views-and-instead-of-update-trigger-limitation-why?forum=transactsql

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

在復雜特徵組合的邊緣努力是找到邊緣情況錯誤的好方法。

引用自:https://dba.stackexchange.com/questions/306657