从 SQL 服务器中派生的 table 删除?

Delete from a derived table in SQL Server?

我正在研究postIN operator in SQL Statement Does not work?的答案中的查询,如下:

DELETE t
    FROM (SELECT t.*,
                 ROW_NUMBER(*) OVER (PARTITION BY P ORDER BY ABS((P & 0xFFFFFFFF) * 256 - F) as seqnum
          FROM MyTable t
         ) t
     WHERE seqnum > 1;

经过多次研究,我终于弄清楚了大部分问题,并将查询修改如下:

DELETE t2
    FROM (SELECT t.*,
                 ROW_NUMBER() OVER (PARTITION BY P ORDER BY ABS((P & 0xFFFFFFFF) * 256 - F)) as seqnum
          FROM MyTable t
         ) t2
     WHERE seqnum > 1;

变化是:

  1. 在 "F)" 后添加“)”,以便 "OVER (PARTITION BY P ORDER BY ABS((P & 0xFFFFFFFF) * 256 - F))" 遵循 https://docs.microsoft.com/en-us/sql/t-sql/queries/select-over-clause-transact-sql?view=sql-server-ver15
  2. 处的语法
  3. 将 ROW_NUMBER(*) 更改为 ROW_NUMBER(),因为上面的文档使用了 ROW_NUBMER()。
  4. 将外部查询中的 t 更改为 t2。 FROM子句中的子查询必须有别名,所以子查询后必须有别名。参见 . Moreover, actual the alias in the outer query can be same as the one in the subquery, see https://dba.stackexchange.com/questions/16516/subqueries-aliases-same-as-main-queries-aliases,但它们指的是不同的对象。所以我将外部查询中的别名从 "t" 更改为 "t2"

复杂查询中的很多知识对于新手来说理解起来有点困难。另外,我还有两点不是很理解

  1. 为什么我必须写 "Delete t2 FROM" 而不是 "Delete FROM"?我只找到这个 link Difference between DELETE and DELETE FROM in SQL? ,但它用于 JOIN table,而不是用于子查询。
  2. https://dba.stackexchange.com/questions/120233/sql-server-delete-from-subquery-derived-table 的 link,我知道子查询是派生的 table。那么t2的DELETE只是从一个derviedtable(它是虚拟的)中删除记录,为什么它也可以对底层真实的table MyTable进行相同的删除操作?

谢谢

"Why I must write "Delete t2 FROM" instead of "Delete FROM"?

最简单的方法是首先编写一个进行选择的查询,然后从中删除,例如使用 CTE:

WITH cte AS (
   SELECT * 
   FROM (
     SELECT t.*,
       ROW_NUMBER() OVER (PARTITION BY P ORDER BY ABS((P & 0xFFFFFFFF) * 256 - F)) as seqnum
     FROM MyTable t) sub
   WHERE seqnum > 1
)
SELECT * FROM cte; -- selecting
--DELETE FROM cte; -- deletion, no where condition, only the ones selected will be removed

Then the DELETE from t2 is just delete records from a dervied table(it is virtual), why it can also perform the same deletion operation on the underlying real table MyTable?

这与从视图中删除类似。只要 SQL 操作保留键(无聚合、DISTINCT、n:m 关系),就可以从派生 table 中删除行。

在这种情况下,添加 window 函数会引入一个新列,但它始终是 1:1 到现有数据。

Why I must write "Delete t2 FROM" instead of "Delete FROM"?

是因为DELETE syntax

DELETE   
    [ FROM ]   <--optional keyword FROM
    { { table_alias  
      | <object>   <--> <object> ::= table_or_view_name
      | @table_variable 
    }
    [ FROM table_source [ ,...n ] ]  <-- note the whole FROM statement is optional, not only the FROM keyword
......

FROM table_source
Specifies an additional FROM clause. **This Transact-SQL extension to DELETE** allows specifying data from <table_source> and deleting the corresponding rows from the table in the first FROM clause.

DELETE(可选 FROM)并且可以使用 table 别名 或 table 或视图

的对象

DELETE 后没有派生 table/table_source,因此(从派生 table 中删除)唯一适用的选项是使用别名。 第二个 FROM 接受一个 table_source,它可以是一个派生的 table。 因此,在派生 table

的情况下
DELETE [FROM] alias
FROM (....) as alias

why it can also perform the same deletion operation on the underlying real table MyTable

只要导出的table保持每行的粒度(每行可以单独标识)并且dml的范围限制在单个table(考虑到派生 table 定义)然后对派生 tables、视图、ctes 进行 dml 操作是可能的。