SQL Server - 为什么更新语句中不允许使用窗口函数?

Nei*_*l P 10 sql-server sql-server-2014

运行更新语句时,例如下面的语句,我收到一条错误消息,告诉我

窗口函数只能出现在 SELECT 或 ORDER BY 子句中。

UPDATE dbo.Dim_Chart_of_Account
SET Account_Order = LAG([Account_Order]) OVER (ORDER BY [Account_SKey])
Run Code Online (Sandbox Code Playgroud)

我知道这可以使用可更新的 cte 轻松解决,如下所示

 WITH my_cte AS (
     SELECT [Account_Order], LAG([Account_Order]) OVER (ORDER BY [Account_SKey]) AS acc_order_lag
     FROM Dim_Chart_of_Account
)
UPDATE my_cte
SET [Account_Order] = acc_order_lag
Run Code Online (Sandbox Code Playgroud)

我的问题是,是否有任何原因在更新语句中不允许这样做,我是否应该避免使用可更新的 cte 作为解决方法?

我担心的是在使用带有更新语句的窗口函数时会出现问题,因此我想了解这是一种可接受的方法还是应该避免的方法。

Dou*_*ane 5

UPDATE 语句中不允许使用窗口函数,因为 UPDATE 与 SELECT 或 ORDER BY 不兼容。

窗口函数就像作用域 SELECT 语句,它重新检查相关行并应用 PARTITION BY 和 ORDER BY 等条件。此外,许多窗口函数需要 ORDER BY 子句(例如 ROW_NUMBER、LAG 和 FIRST_VALUE)。

UPDATE 语句使用 SET 而不是 SELECT,因此在同一查询级别中的任何地方都不允许使用 SELECT。任何与 UPDATE 一起出现的 SELECT 必须包含在子查询中。

考虑到 UPDATE 语句与其更新行的顺序无关,因此禁止 ORDER BY 是有意义的。

使用 CTE 或其他子查询作为获取 UPDATE 以使用窗口函数的解决方法没有固有的缺点。这是 Itzik Ben-Gan 等 T-SQL 专家提倡的常见做法。(请参阅他的书Microsoft SQL Server 2012 High-Performance T-SQL Using Window Functions 的第 29 页,其中他涵盖了这个确切的场景。)