27

谁能解释为什么我们不能在group by子句中使用窗口函数以及为什么它只允许在SELECTandORDER BY

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

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

我收到一个错误

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

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

4

2 回答 2

20

加窗函数在 ANSI 规范中定义为在处理 , , 之后GROUP BY逻辑HAVING执行WHERE

更具体地说,它们在此处的逻辑查询处理流程图的步骤 5.1 和 6 中被允许。

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

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 = 1NtileForGroupBy = 1

于 2013-01-01T21:44:30.877 回答
18

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

select  invoice
,       rn
from    (
        select  Invoice
        ,       row_number() over(order by Invoice) as rn
        from    Table1
        ) as SubQueryAlias
group by
        invoice
,       rn
于 2013-01-01T14:45:41.433 回答