每个 GROUP BY 限制 SQL 查询
Posted
技术标签:
【中文标题】每个 GROUP BY 限制 SQL 查询【英文标题】:LIMIT SQL query per GROUP BY 【发布时间】:2013-05-31 02:16:01 【问题描述】:我有 20 个教室,每个教室有 50 名学生。
是否有可能在单个查询语句中找到每个教室中的 10 名最佳学生?
表格“klas”:
int id
int cla_id
int stu_id
int final_score
【问题讨论】:
您使用的是哪个 RDBMS? SQL Select only rows with Max Value on a Column的可能重复 @sgeddes mssql 和 postgresql 【参考方案1】:在大多数数据库中,您可以这样做:
select k.*
from (select k.*,
row_number() over (partition by cla_id order by final_score desc) as seqnum
from klas
) k
where seqnum <= 10;
这会检索每个班级的 10 名得分最高的学生。它不适用于 mysql 和 MS Access 等不支持 ANSI 标准窗口函数(如 row_number()
)的数据库。
row_number()
函数对行应用顺序编号。在您的情况下,每个 cla_id
的编号都会重新开始 - 因为 partition by
子句。编号为“1”的行是具有最大final_score
的行——因为order by final_score desc
。这也可以应用于聚合函数,如 min()
和 sum()
。在这种情况下,它会在原始数据集的每一行上提供聚合值(相当于进行聚合和连接,但通常效率更高)。
【讨论】:
@KiswonoPrayogo:它被称为“窗口函数”,现在每个现代 DBMS 都支持这一点。 Postgres 手册有一个很好的教程:postgresql.org/docs/current/static/tutorial-window.html【参考方案2】:如果第 10 名最好的学生与第 11 名或第 12 名的分数相同,您不想只返回数字 10,还希望返回 11 和 12。所以在这种情况下最好使用 RANK(),如下所示:
;WITH ranking
AS
(
SELECT *
,RANK() OVER (PARTITION BY cla_id
ORDER BY final_score DESC) AS rank
FROM klas
)
SELECT cla_id
,rank
,stu_id
FROM ranking
WHERE rank <= 10
ORDER BY cla_id
,rank
【讨论】:
dense_rank()
甚至会更好(;
应该放在语句的末尾,而不是 Postgres 的开头,但是你应该习惯于编写语句的标准方式使用 MS 工具时:sqlblog.com/blogs/aaron_bertrand/archive/2009/09/03/…)
@a_horse_with_no_name:dense_rank() 将返回所有得分最高的 10 个学生。这不是所要求的。
不,不会的。 rank() 将“跳过”值,因此如果您有值 12,12,10,9,rank()
将返回 1,1,3,4,而 dense_rank()
将返回 1,1,2,3。 rank()
可能没有“第 10”位。
@a_horse_with_no_name:嗯,你正确描述的是原因,为什么dense_rank()
会错误。 We've had this topic on SO before.
注意:前导 ;
仅在 SQL-Server 中有效。其余的也可以在 PostgreSQL 中使用。以上是关于每个 GROUP BY 限制 SQL 查询的主要内容,如果未能解决你的问题,请参考以下文章
SQL数据库中查询语句Order By和Group By有啥区别
SQL 查询 - GROUP BY , PARTITION BY