每个 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 查询的主要内容,如果未能解决你的问题,请参考以下文章

使用 group by 和条件优化 SQL 查询

SQL数据库中查询语句Order By和Group By有啥区别

SQL 查询 - GROUP BY , PARTITION BY

Oracle SQL查询到GROUP BY并减去?

当sql语句中where,order by,group by同时使用查询sql语句中三者的顺序

SQL -- WHERE、GROUP BY、HAVING 查询