如何使用子查询进行 SQL 删除

Gre*_*reg 15 sql-server subquery sql-server-2014

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

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
Run Code Online (Sandbox Code Playgroud)

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

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

ype*_*eᵀᴹ 14

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

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

虽然有限制,但这是意料之中的。想象一下,如果subquery是 2 个(或 17 个表)的连接。那会delete是什么意思?(应该从哪些表中删除行?)可更新的视图是一件非常复杂的事情。最近(2012 年)出版了一本完全关于这个主题的书,由著名的关系理论专家 Chris Date 撰写:查看更新和关系理论

当派生表(或视图)是一个非常简单的查询时,比如它只有一个基表(可能受 a 限制WHERE)并且没有GROUP BY,那么派生表的每一行都对应于底层基表中的一行,所以它是容易*更新、插入或删除。

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

对于 SQL Server,您可以在 MSDN 的可更新视图段落中阅读更多内容:CREATE VIEW

可更新的视图

您可以通过视图修改底层基表的数据,只要满足以下条件即可:

  • 任何修改,包括UPDATEINSERTDELETE语句,都必须仅引用一个基表中的列。

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

  • 聚合函数:AVGCOUNTSUMMINMAXGROUPINGSTDEVSTDEVPVAR、 和VARP

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

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

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

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


实际上deleteupdate. SQL Server 只需要主键或某种其他方式来标识要删除基表的哪些行。对于update,还有一个额外的(相当明显的)限制,我们不能更新计算列。您可以尝试修改您的查询以进行更新。更新CreatedDateTime可能会正常工作,但尝试更新计算RowNumber列会引发错误。而且insert是更为复杂,因为我们不得不为所有的基表没有一列提供值DEFAULT约束。