这个问题很老,但是是referenced in a new question on dba.SE。我觉得没有提供最好的解决方案。此外,还有更快的新选项。
标题中的问题
我可以在 SQL 中执行max(count(*)) 吗?
是的,您可以通过在 window function 中嵌套聚合函数来实现:
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小提琴here
这是标准 SQL。 Postgres 在 8.4 版(2009-07-01 发布,在提出这个问题之前)引入了它。其他 RDBMS 应该能够做到这一点。
考虑SELECT 查询中的事件顺序:
可能的缺点:窗口函数不聚合行。在聚合步骤之后,您会得到 all 行。在某些查询中很有用,但不适合这个查询。
要获得计数最高的一行,您可以使用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 的实现各不相同:
或者您可以每组一行使用DISTINCT ON(仅限 Postgres)获得最高计数:
实际问题
我需要获取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小提琴here
PostgreSQL 13 使用标准 SQL 语法添加了 WITH TIES:
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小提琴here
这应该是最快的查询。延伸阅读:
要按附加条件对结果进行排序(或者对于旧版本的 Postgres 或其他没有 WITH TIES 的 RDBMS),请在子查询中使用窗口函数 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 都支持窗口函数。