如何从计数中选择具有最大产生值的行
Posted
技术标签:
【中文标题】如何从计数中选择具有最大产生值的行【英文标题】:How to select a row with the maximum produced value from count 【发布时间】:2012-11-24 19:26:00 【问题描述】:我对 mysql 有点陌生,所以我被困在一个查询上。 我从一个名为歌曲的数据库中获得了这张表(我只能在这个数据库中读取):
table name:cd_production
code_cd etaireia etos
______________________
400400 ODEON 1987
400401 ODEON 1986
400412 COLUMBIA 1990
400420 COLUMBIA 1990
400657 LYRA 1965
410000 COLUMBIA 1962
410001 COLUMBIA 1964
410003 PHILIPS 1979
410005 PHILIPS 1971
420430 ODEON 2002
420440 LYRA 2005
420450 COLUMBIA 2009
420460 ODEON 2007
420470 PHILIPS 2008
420480 ODEON 2002
420490 COLUMBIA 2010
500500 SONY 1968
500510 SONY 1972
600601 COLUMBIA 1962
600602 COLUMBIA 1963
600603 ODEON 1964
670670 PHILIPS 1983
并且我想找到产生的 cd 数量最多的 etaireia(意味着每个 etaireia 的 code_cd 不同)。 请问
select etaireia ,count(all code_cd) as cds
from cd_production
group by etaireia
我得到一个返回列的列表
etaireia cds
________________
COLUMBIA 8
LYRA 2
ODEON 6
PHILIPS 4
SONY 2
这有点正确,但我不知道如何只获得具有最大 cd 的 etaireia,例如
etaireia cds
________________
COLUMBIA 8
这里有什么诀窍? 我不想使用 LIMIT 1 方法,因为它不是通用的。 提前致谢
【问题讨论】:
如果您有多个具有相同最大计数的行,是否要检索所有行? @MichaelBerkowski 是的,我想要 :) 好的,我更新了答案。 【参考方案1】:如果您希望找到所有记录及其计数最大的计数,您可以在HAVING
子句中使用子查询来确定COUNT()
的MAX()
值是多少。
SELECT
etaireia,
COUNT(*) AS cds
FROM
cd_production
GROUP BY etaireia
HAVING cds = (
SELECT MAX(cds)
FROM (SELECT etaireia, COUNT(*) as cds
FROM cd_production
GROUP BY etaireia) subq
)
http://sqlfiddle.com/#!2/869b4/4
限制为单行的方法因 RDBMS 而异。 MySQL 使用LIMIT
,MSSQL 使用TOP
,Oracle 使用ROWNUM
...使用RDBMS 特定的方法使这变得简单很多,因为您不需要在HAVING
子句中嵌套子查询。相反,您可以在HAVING
子查询中使用LIMIT
来仅返回一个最大的COUNT()
,而无需包装另一个查询以获取MAX()
。
SELECT
etaireia,
COUNT(*) AS cds
FROM
cd_production
GROUP BY etaireia
HAVING cds = (
SELECT COUNT(*)
FROM cd_production
GROUP BY etaireia
ORDER BY COUNT(*) DESC
LIMIT 1
)
and here is the MySQL-specific version...
【讨论】:
对不起,我注意到我不想使用 limit 1 方法导致其错误。如果多个原始数据具有相同的最大值怎么办?它不起作用。 打破名称的关系。但它会产生复杂的查询。 @michael berkowski 我不明白。它不起作用。该查询假定 cd 已存在于表中,但事实并非如此。 cds 列是输出 我认为它的错误用法。 have 仅应用于查询的输出,而不是在服务器中。 @GeoPapas HAVING 在聚合之后应用,因此在COUNT(*)
之后但仍在服务器上,而不是您的应用程序代码上。它确实 工作,如 SQLFiddle 链接中所示。你是什么意思它假设CD已经存在?无论表中有多少,该值都是正确的。通过从 SQLFiddle 的示例中删除行进行测试。例如:sqlfiddle.com/#!2/b1f37/1【参考方案2】:
应该在大多数 DBMS 中运行的其他“通用”方式(并且不要使用 MYSQL 特定的LIMIT
关键字):
SELECT
etaireia,
COUNT(*) AS cds
FROM
cd_production c
GROUP BY
etaireia
HAVING
COUNT(*) >= ALL
( SELECT COUNT(*)
FROM cd_production cc
GROUP BY cc.etaireia
) ;
还有这个:
SELECT
etaireia,
COUNT(*) AS cds
FROM
cd_production c
GROUP BY
etaireia
HAVING
NOT EXISTS
( SELECT *
FROM cd_production cc
GROUP BY cc.etaireia
HAVING COUNT(*) > COUNT(DISTINCT c.code_cd)
) ;
都在 SQL-Fiddle 中测试:test-1(适用于所有 4 个:Postgres、SQL-Server、Oracle、MySQL,除了不在 Postgres 中运行的第二个查询)。
对于那些具有窗口函数(和OVER
子句)的 DBMS,还有另一种方法(适用于 Postgres、Oracle、SQL-Server 2012):
SELECT etaireia, cds
FROM
( SELECT
etaireia, cds,
RANK() OVER (ORDER BY cds DESC) AS rnk
FROM
( SELECT
etaireia,
COUNT(*) AS cds
FROM
cd_production c
GROUP BY
etaireia
) tmp
) tmp2
WHERE rnk = 1 ;
以下是“标准”方式。它应该在支持标准 SQL 语法 FETCH ... OFFSET
(相当于供应商特定的 LIMIT
和 TOP
)的 Postgres 和 SQL-Server 中工作:
SELECT
etaireia,
COUNT(*) AS cds
FROM
cd_production AS c
GROUP BY
etaireia
ORDER BY
cds DESC
OFFSET 0 ROWS
FETCH FIRST 1 ROWS ONLY ;
都在 SQL-Fiddle 中测试:test-3(Q4 在 Postgres 和 SQL-Server 2012 中工作)。
请注意,这将给出与前 3 个查询不同的结果,因为 FETCH
语法不解析平局,只返回平局中的一行。
【讨论】:
【参考方案3】:那么只选择第一个:
select Top 1 etaireia ,count(all code_cd) as cds
from cd_production
group by etaireia
忽略,因为你不想使用限制。
【讨论】:
似乎不适用于“Top”关键字。 :(也许它不被数据库支持 mysql 不使用TOP
,除此之外与使用LIMIT
的意图相同,OP 要求不要使用它以上是关于如何从计数中选择具有最大产生值的行的主要内容,如果未能解决你的问题,请参考以下文章
如何提高 SQL Server 查询的性能以选择具有值的行不在子查询中的一次计数