允许对连接表进行合并删除,但有一个错误

Cha*_*ace 5 sql-server delete t-sql merge derived-tables

首先,可更新的 CTE、派生表或视图可以直接作为目标UPDATE,即使它具有多个基表,只要所有列都来自同一源表。

DELETE但即使仅选择一个表中的列,它们也不能成为 a 的目标。

Msg 4405 Level 16 State 1
View or function 'x' is not updatable because the modification affects multiple base tables.
Run Code Online (Sandbox Code Playgroud)

为了绕过这个限制,我尝试MERGE对虚拟表使用 a 。(显然,这个简单的示例可以使用DELETE...WHERE EXISTS或通过将一个表作为合并源来编写,但这一点是正确的。使用了原始示例,ROW_NUMBER因此这些是不可能的。)

WITH Joined AS (
    SELECT t1.*
    FROM t1
    JOIN t2 ON t2.id1 = t1.id1
)
MERGE Joined
USING (VALUES(0)) v(dummy) ON 1=0
WHEN NOT MATCHED BY SOURCE THEN DELETE;
Run Code Online (Sandbox Code Playgroud)

数据库<>小提琴

这实际上是被允许的。但我发现被修改的表并不依赖于所选择的列或其顺序。这完全取决于表的连接顺序

在我看来,这似乎是完全错误的行为。

实验THEN UPDATE显示了更明智的行为:它取决于子句中使用的列THEN UPDATE,与普通语句相同UPDATE

所以,我认为 SQL Server 应该:

  • 要么继续允许删除可更新的 CTE,但确保仅选择一个表的列(如UPDATE),以确保没有歧义。
  • 或者当源是具有多个基表的可更新 CTE 时THEN DELETE完全不允许。MERGE

我对可更新视图的工作方式是否有一些误解,或者这里是否存在实际错误?


现已在 Azure 反馈上提交错误报告。请在这里投票

Pau*_*ite 6

从一方面来看,你的问题是无法回答的,因为这取决于MERGE设计意图。文档中没有任何内容可以明确解决这种情况。

我的观点是,它的MERGE行为应该与非选项相同MERGE;也就是说DELETE 应该被禁止

table_or_view_name
要从中删除行的表或视图的名称。

表变量在其范围内也可以用作DELETE语句中的表源。

table_or_view_name引用的视图必须是可更新的,并且在视图定义的子句中恰好引用一个基表FROM

(强调已添加)

这里不会产生错误的事实MERGE可能是因为解析器很难检测到条件。或者这是一种疏忽,正如变化的异常复杂性所常见的那样MERGE

无论如何,我的立场是,在找到“有效”的方法之前,您应该避免解决不允许的行为。或者,您不应该对任何奇怪或不确定的结果感到惊讶。

将该问题作为错误报告给 Microsoft,以便他们进行调查。