【问题标题】:Windowed functions can only appear in the SELECT or ORDER BY clauses窗口函数只能出现在 SELECT 或 ORDER BY 子句中
【发布时间】:2012-12-16 04:29:05
【问题描述】:

谁能解释为什么我们不能在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(),但我想知道为什么我们不能分组使用它?

【问题讨论】:

  • row_number() 分组有什么意义?每个项目将单独在一个组中。不过,这个问题很合理。
  • 如果我有重复的发票要考虑,在这种情况下我也想保留它。你可以想,那我为什么要分组。问题是我想知道为什么会这样?为什么我们不能在 group by 中使用窗口函数?
  • 它将如何产生歧义。你可以解释吗?如果我只想在 where 子句中选择排名值 2。怎么会造成歧义
  • 那么你想在 where 子句中使用它而不是 group by then?
  • 窗口函数在 ANSI 规范中定义为在处理 GROUP BY, HAVING, WHERE 之后逻辑执行,我猜他们可以用另一种方式定义它并允许 GROUP BY 使用在与SELECT 使用的窗口不同,但这肯定会很混乱?

标签: sql sql-server


【解决方案1】:

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

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

【讨论】:

  • 是的,兄弟。我知道这一点,我担心的是为什么我们不能在查询中使用它?为什么要这样设计?
  • 好吧,SQL Server 甚至无法解析where 子句中的简单别名。例如,这不起作用:select datediff(day,col1,col2) as ddiff from YourTable where ddiff > 1。我认为这是他们解析器的某种限制。
  • 嗯,我从来不知道。感谢您对此的澄清:)
  • “rn”不应该也在外部选择中吗?
  • 不应该将发票添加到组中或从选择或聚合中删除吗?
【解决方案2】:

在 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

【讨论】:

  • 逻辑查询处理流程图非常有用。谢谢@Martin,你的解释很有道理:)
  • 现在逻辑查询处理流程图..LINK坏了
  • @HaveNoDisplayName 如果您搜索"Logical Query Processing Poster" filetype:pdf,看起来好像有几个人复制了。
  • abhijitmore.files.wordpress.com/2010/03/… 找到它,有趣的是,顶部出现在图表中,需要在订购之前完成。很奇怪。
  • @Alex - 我认为这只是一个错误。该网站列出了同一作者 (Itzik Ben Gan) 的新订单,该订单更正了这一点。 porterwebsites.com/sql-server-logical-query
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-06-14
  • 1970-01-01
  • 1970-01-01
  • 2017-12-22
相关资源
最近更新 更多