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


10

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

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

UPDATE dbo.Dim_Chart_of_Account
SET Account_Order = LAG([Account_Order]) OVER (ORDER BY [Account_SKey])

我知道可以使用可更新的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

我的问题是,是否有任何原因为什么不允许在更新语句中使用此方法,我应该避免使用可更新的CTE作为解决方法吗?

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


1
可更新的CTE可以接受并且很好。不知道为什么不允许在UPDATE中使用它。
ypercubeᵀᴹ

2
也许是万圣节的某种保护?
亚伦·伯特兰

Answers:


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高性能T-SQL》第29页,其中涵盖了此确切方案。)

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.