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

时间:2013-01-01 14:33:02

标签: sql sql-server

任何人都可以解释为什么我们不能在group by子句中使用窗口函数以及为什么只允许SELECTORDER BY

我试图根据row_number()和SQL Server中的一列对记录进行分组,如下所示:

SELECT Invoice
from table1
group by row_number() over(order by Invoice),Invoice

我收到错误

  

窗口函数只能出现在SELECT或ORDER BY

我可以在SELECT子句中选择此row_number(),但我想知道为什么我们不能将它分组使用?

2 个答案:

答案 0 :(得分:17)

在ANSI规范中定义了窗口函数,以便在处理GROUP BYHAVINGWHERE之后逻辑执行。

更具体地说,Logical Query Processing flow chart here中的步骤5.1和6允许这样做。

我想他们可以用另一种方式定义它并允许GROUP BYWHEREHAVING使用窗口函数,窗口是该阶段开始时的逻辑结果集但是假设他们有,我们被允许构建诸如

之类的查询
SELECT a, 
       b, 
       NTILE(2) OVER (PARTITION BY a ORDER BY b) AS NtileForSelect
  FROM YourTable
  WHERE NTILE(2) OVER (PARTITION BY a ORDER BY b) > 1
  GROUP BY a, 
           b, 
           NTILE(2) OVER (PARTITION BY a ORDER BY b)
  HAVING NTILE(2) OVER (PARTITION BY a ORDER BY b) = 1

有四个不同的逻辑窗口,祝你好运,看看结果如何!另外,如果在HAVING中您实际上想要按照上面GROUP BY级别的表达式进行过滤,而不是将行窗口作为GROUP BY之后的结果?

CTE版本更详细,但更明确,更容易理解。

WITH T1 AS
(
SELECT a, 
       b, 
       NTILE(2) OVER (PARTITION BY a ORDER BY b) AS NtileForWhere
  FROM YourTable
), T2 AS
(
SELECT a,
       b,
       NTILE(2) OVER (PARTITION BY a ORDER BY b) AS NtileForGroupBy
FROM T1
WHERE NtileForWhere > 1
), T3 AS
(
SELECT a,
       b,
       NtileForGroupBy,
       NTILE(2) OVER (PARTITION BY a ORDER BY b) AS NtileForHaving
FROM T2
GROUP BY a,b, NtileForGroupBy
)
SELECT a,
       b,
       NTILE(2) OVER (PARTITION BY a ORDER BY b) AS NtileForSelect
FROM T3
WHERE NtileForHaving = 1

由于这些都是在SELECT声明中定义的并且有别名,因此可以轻松实现消除不同级别结果的歧义,例如只需将WHERE NtileForHaving = 1切换为NtileForGroupBy = 1

即可

答案 1 :(得分:16)

您可以通过将窗口函数放在子查询中来解决这个问题:

select  invoice
,       rn
from    (
        select  Invoice
        ,       row_number() over(order by Invoice) as rn
        from    Table1
        ) as SubQueryAlias
group by
        invoice
,       rn