SQL如何使用子查询删除


15

我们的开发人员之一添加了以下代码,以从表中删除重复的记录:

DELETE  SubQuery

FROM
(
    SELECT  ID
            ,FK1
            ,FK2
            ,CreatedDateTime
            ,ROW_NUMBER() OVER(PARTITION BY FK1, FK2 ORDER BY CreatedDateTime) AS RowNumber

    FROM    Table
)
AS SubQuery

WHERE   RowNumber > 1

查看代码时,我认为它不起作用,但是在我们的测试环境(SQL 2014)中对其进行测试表明它可以!

SQL如何知道如何解析子查询并从中删除记录table

Answers:


14

subquery你有你的代码被称为派生表。它不是基表,而是在查询运行期间“存在”的表。就像视图(也称为查看表)一样,在最新版本的CTE中,它是在查询中“定义”表的另一种第四种方法,它们在许多方面都类似于表。您可以select从中使用它们,也可以在其他表中使用它们,也可以fromjoin它们用于其他表(是否为基!)。

在某些DBMS中(并非所有DBMS都以相同的方式实现),这些表/视图是可更新的。而“更新”的意思,我们也可以updateinsert进入或delete从他们。

虽然有限制,但这是预期的。想象如果subquery是2(或17个表)的联接。那是什么delete意思呢?(应该从哪些表中删除行?)可更新视图是非常复杂的事情。最近有一部有关该主题的新书(2012年),是由关系理论领域的著名专家克里斯·伊达斯(Chris Date)撰写的:《视图更新和关系理论》

如果派生表(或视图)是一个非常简单的查询,例如它只有一个基表(可能受a限制WHERE),而no GROUP BY,则派生表的每一行都对应于基础基表中的一行,因此它是易于*进行更新,插入或删除。

当子查询中的代码更复杂时,它取决于是否可以将派生表/视图的行跟踪/解析为来自基础基表之一的行。

对于SQL Server,可以在MSDN的“可更新视图”段落中阅读更多信息:CREATE VIEW

可更新的视图

只要满足以下条件,就可以通过视图修改基础基表的数据:

  • 包括UPDATEINSERTDELETE语句在内的任何修改都只能引用一个基本表中的列。

  • 在视图中修改的列必须直接引用表列中的基础数据。不能以任何其他方式派生这些列,例如通过以下方式:

  • 一个聚集函数:AVGCOUNTSUMMINMAXGROUPINGSTDEVSTDEVPVAR,和VARP

  • 计算。无法从使用其他列的表达式中计算出该列。由使用所述一组符构成的列UNIONUNION ALLCROSSJOINEXCEPT,和INTERSECT 量的计算,并且也不能更新。

  • 被修改的列不受GROUP BYHAVINGDISTINCT条款。

  • TOP在视图的select_statement中未与WITH CHECK OPTION子句一起使用。

前面的限制适用于FROM视图子句中的任何子查询,就像它们适用于视图本身一样。通常,数据库引擎必须能够明确跟踪从视图定义到一个基本表的修改。


实际上delete比起来更容易,更简单update。SQL Server只需要主键或其他方法来标识要删除基表的哪些行。对于update,还有一个附加的(相当明显的)限制,即我们无法更新计算列。您可以尝试修改查询以进行更新。更新CreatedDateTime可能会正常工作,但是尝试更新计算RowNumber列将引发错误。而且insert甚至更加复杂,因为我们必须为基本表的所有没有DEFAULT约束的列提供值。


4

当您查看查询计划时,很容易看到。在您的情况下,计划仅包含一个附加的“段和序列项目”运算符来处理行号。仅当SQL Server实际上可以解析基础表时,这种类型的操作才有效。

完全支持从子查询和CTE中删除,并且非常有效,特别是对于删除重复项。我似乎还记得在旧版本的SQL Server上使用它。

在我的旧博客文章中有更多内容。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.