什么时候可以在标准 SQL 中嵌套聚合函数?

When can aggregate functions be nested in standard SQL?

我知道 SQL-92 不允许这样做。但从那时起它可能已经改变,特别是当应用了 window 时。您能否解释这些更改并提供引入这些更改的版本(或版本,如果有的话)?

例子

  1. Is SUM(COUNT(votes.option_id)) OVER() valid syntax per standard SQL:2016 (or earlier)?

这是我的comment (unanswered, an probably unlikely to in such an old question) in Why can you nest aggregate functions when using a window function in PostgreSQL?

  1. Calculating Running Total (SQL) kata at Codewars 最受好评的解决方案(使用 PostgreSQL 13.0,一个高度符合标准的引擎,因此代码很可能是标准的)这个:
SELECT
  CREATED_AT::DATE AS DATE,
  COUNT(CREATED_AT) AS COUNT,
  SUM(COUNT(CREATED_AT)) OVER (ORDER BY CREATED_AT::DATE ROWS UNBOUNDED PRECEDING)::INT AS TOTAL
FROM
  POSTS
GROUP BY
  CREATED_AT::DATE

(可以简化为:

SELECT
  created_at::DATE date,
  COUNT(*) COUNT,
  SUM(COUNT(*)) OVER (ORDER BY created_at::DATE)::INT total
FROM posts
GROUP BY created_at::DATE

我假设 :: 是我不知道的用于转换的新语法。现在允许从 TIMESTAMP 转换为 DATE(在 SQL-92 中不允许)。)

  1. 正如 this SO answer 所解释的那样,即使没有 window,Oracle 数据库也允许它从上下文中拉入 GROUP BY。不知道标准是否允许。

您自己已经注意到了不同之处:一切都与 window 有关。例如,没有 OVER 子句的 COUNT(*) 是聚合函数。 COUNT(*) 带有 OVER 子句是一个 window 函数。

通过使用聚合函数,您可以压缩在 FROM 子句和 WHERE 子句应用于 GROUP BY 中的指定组或应用于 GROUP BY 中的一行之后获得的原始行缺少 GROUP BY 子句。

Window 函数,又名解析函数,随后应用。他们不会更改结果行的数量,而只是通过查看 selected 数据的所有或部分行 (window) 添加信息。

SELECT
    options.id,
    options.option_text,
    COUNT(votes.option_id) as vote_count,
    COUNT(votes.option_id) / SUM(COUNT(votes.option_id)) OVER() * 100.0 as vote_percentage
FROM options
LEFT JOIN votes on options.id = votes.option_id
GROUP BY options.id;

我们首先将选票加入选项,然后通过将加入的行聚合为每个选项的一个结果行来计算每个选项的选票 (GROUP BY options.id)。我们指望投票 table(COUNT(votes.option_id) 中的不可空列,因此如果没有投票,我们将获得零计数,因为在外部连接的行中,该列设置为空。

在聚合所有行并因此每个选项获得一行之后,我们在此结果集上应用 window 函数 (SUM() OVER)。我们通过查看整个结果集(空 OVER 子句)对投票数应用解析 SUMSUM(COUNT(votes.option_id))),从而在每一行中获得相同的总投票数。我们使用这个计算值:选项的票数除以总票数乘以 100,即选项占总票数的百分比。

PostgreSQL 查询非常相似。我们 select 每个日期的帖子数量(COUNT(created_at) 只不过是 COUNT(*))以及这些计数的总数 运行(通过使用 window 查看直到当前行的所有行)。

因此,虽然这看起来像是我们嵌套了两个聚合函数,但实际上并非如此,因为 SUM OVER 不被视为聚合函数,而是 analytic/window 函数。

Oracle 确实允许将聚合函数直接应用于另一个函数,从而对先前按聚合分组的函数调用最终聚合。这允许我们得到一个结果行,比方说,总和的平均值,而不必为此编写子查询。然而,这不符合 SQL 标准,并且即使在当时的 Oracle 开发人员中也很不受欢迎。