这个问题很旧,但在 dba.SE 的一个新问题中被引用。我觉得没有提供最好的解决方案。此外,还有新的、更快的选择。
标题中的问题
我可以max(count(*))
在 SQL 中做一个吗?
是的,您可以通过在窗口函数中嵌套聚合函数来实现:
SELECT m.yr, count(*) AS movie_count
, max(count(*)) OVER () AS max_ct
FROM casting c
JOIN movie m ON c.movieid = m.id
WHERE c.actorid = (SELECT id FROM actor WHERE name = 'John Travolta')
GROUP BY m.yr
ORDER BY count(*) DESC;
db<>在这里摆弄
那是标准 SQL。Postgres 在 8.4 版(发布于 2009-07-01,在提出这个问题之前)引入了它。其他 RDBMS 应该能够做到这一点。考虑SELECT
查询中的事件顺序:
可能的缺点:窗口函数不聚合行。在聚合步骤之后,您将获得所有行。在某些查询中很有用,但不适合这个查询。
要获得最高计数的一行,您可以使用ORDER BY ct LIMIT 1
:
SELECT c.yr, count(*) AS ct
FROM actor a
JOIN casting c ON c.actorid = a.id
WHERE a.name = 'John Travolta'
GROUP BY c.yr
ORDER BY ct DESC
LIMIT 1;
仅使用基本的 SQL 功能,在任何中等体面的 RDBMS 中都可用 -LIMIT
实现各不相同:
或者,您可以使用(仅 Postgres)每组获得最高计数的一行:DISTINCT ON
实际问题
我需要获取count(*)
最大的行。
计数最高的可能不止一行。
SQL Server拥有该功能WITH TIES
已有一段时间了 - 使用非标准语法:
SELECT TOP 1 WITH TIES
m.yr, count(*) AS movie_count
FROM casting c
JOIN movie m ON c.movieid = m.id
WHERE c.actorid = (SELECT id FROM actor WHERE name = 'John Travolta')
GROUP BY m.yr
ORDER BY count(*) DESC; -- can't sort by year for this
db<>在这里摆弄
PostgreSQL 13添加WITH TIES
了标准 SQL 语法:
SELECT m.yr, count(*) AS movie_count
FROM casting c
JOIN movie m ON c.movieid = m.id
WHERE c.actorid = (SELECT id FROM actor WHERE name = 'John Travolta')
GROUP BY m.yr
ORDER BY count(*) DESC -- can't sort by year for this
FETCH FIRST 1 ROWS WITH TIES;
db<>在这里摆弄
这应该是最快的查询。进一步阅读:
要按附加条件(或旧版本的 Postgres 或其他不带 的 RDBMS)对结果进行排序,请在子查询中WITH TIES
使用窗口函数:rank()
SELECT yr, movie_count
FROM (
SELECT m.yr, count(*) AS movie_count
, rank() OVER (ORDER BY count(*) DESC) AS rnk
FROM casting c
JOIN movie m ON c.movieid = m.id
WHERE c.actorid = (SELECT id FROM actor WHERE name = 'John Travolta')
GROUP BY m.yr
) sub
WHERE rnk = 1
ORDER BY yr; -- optionally sort by year
现在所有主要的 RDBMS 都支持窗口函数。