0

0

SQL 分组查询如何实现每组排名统计?

冷炫風刃

冷炫風刃

发布时间:2025-09-21 20:47:01

|

457人浏览过

|

来源于php中文网

原创

分组排名通过窗口函数实现,核心是使用ROW_NUMBER()、RANK()和DENSE_RANK()结合PARTITION BY与ORDER BY,在每组内进行排序。ROW_NUMBER()为每行分配唯一序号,即使并列也强制区分;RANK()在并列时给予相同排名,但后续排名跳跃;DENSE_RANK()则在并列时相同排名且后续不跳号。实际应用中可根据业务需求选择函数,并通过添加额外排序字段确保结果确定性,广泛用于电商Top N商品、金融最大交易、用户行为路径分析等场景。

sql 分组查询如何实现每组排名统计?

SQL分组查询实现每组排名统计,核心在于运用窗口函数(Window Functions)。这是一种极其强大且灵活的工具,它允许你在不改变原有分组聚合结果的前提下,对每个分组内的数据进行独立的排序和编号,从而轻松地得到你想要的组内排名。

解决方案

要实现每组排名统计,我们通常会用到SQL的窗口函数,特别是

ROW_NUMBER()
RANK()
DENSE_RANK()
。它们在
OVER()
子句中结合
PARTITION BY
来定义分组,再用
ORDER BY
来指定组内的排序规则。

想象一下,我们有一个

students_scores
表,记录了学生在不同课程中的成绩:

CREATE TABLE students_scores (
    student_id INT,
    student_name VARCHAR(50),
    course_id INT,
    course_name VARCHAR(50),
    score INT
);

INSERT INTO students_scores (student_id, student_name, course_id, course_name, score) VALUES
(1, '张三', 101, '数学', 95),
(2, '李四', 101, '数学', 90),
(3, '王五', 101, '数学', 95),
(4, '赵六', 101, '数学', 88),
(5, '钱七', 102, '语文', 80),
(6, '孙八', 102, '语文', 85),
(7, '周九', 102, '语文', 85),
(8, '吴十', 102, '语文', 78),
(9, '郑一', 103, '英语', 92),
(10, '王二', 103, '英语', 92),
(11, '李三', 103, '英语', 89);

现在,我们想知道每个课程里学生的成绩排名。这就是分组排名的典型场景。

SELECT
    student_name,
    course_name,
    score,
    ROW_NUMBER() OVER (PARTITION BY course_name ORDER BY score DESC) AS row_num_rank,
    RANK() OVER (PARTITION BY course_name ORDER BY score DESC) AS rank_rank,
    DENSE_RANK() OVER (PARTITION BY course_name ORDER BY score DESC) AS dense_rank_rank
FROM
    students_scores
ORDER BY
    course_name, score DESC;

这段SQL会按照

course_name
进行分组,然后在每个课程组内,根据
score
降序排列,并计算出三种不同的排名。
PARTITION BY course_name
就是定义了“组”的概念,
ORDER BY score DESC
则指定了组内排名的依据。这种方式非常直观,而且效率通常很高,比早期的子查询或变量赋值方法要优雅得多。

SQL中ROW_NUMBER、RANK和DENSE_RANK函数有何区别

理解这三个窗口函数的细微差别,是掌握分组排名的关键。虽然它们都用于生成排名,但在处理并列(ties)情况时,行为却大相径庭。

  • ROW_NUMBER()
    : 这个函数为分区(组)内的每一行分配一个唯一的、连续的整数。即使有并列的行,它们也会得到不同的排名。你可以把它想象成一个纯粹的行号计数器,遇到并列时,它的排名是“任意”分配的,通常取决于数据在物理存储或查询优化器处理时的顺序(当然,你也可以通过在
    ORDER BY
    子句中添加额外的列来强制一个确定的顺序)。如果你需要从每个组中精确地选出“第N个”元素,哪怕有并列,
    ROW_NUMBER()
    是首选。

  • RANK()
    :
    RANK()
    函数处理并列的方式是,并列的行会获得相同的排名,但下一个非并列的行会跳过相应的排名。举个例子,如果两个人并列第一,他们都会得到排名1,但第三个人会得到排名3(排名2被跳过了)。这种排名方式在传统竞赛中很常见,比如“并列第一,然后是第三名”。

  • DENSE_RANK()
    : 与
    RANK()
    类似,
    DENSE_RANK()
    也为并列的行分配相同的排名。但它与
    RANK()
    不同的是,它不会跳过排名。也就是说,如果两个人并列第一,他们都得到排名1,但第三个人会得到排名2。排名是“紧密”连续的,没有间隔。在某些业务场景下,比如我们想知道“有多少个不同的排名等级”,
    DENSE_RANK()
    会更符合预期。

用我们上面的学生成绩数据来直观感受一下:

金典兑换游戏支付平台程序
金典兑换游戏支付平台程序

本软件完全免费,无任何bug。用户可放心使用,网关需单独注册,请联系软件作者。1、关于接口设置:721K 卡易智能点卡接口,易宝支付网银接口。2、关于账户功能:商户信息管理、玩家留言信箱、网关下载、资金管理。3、关于游戏管理:分区管理、添加分区、分组管理、比例模板、补发管理、获取代码。4、关于订单管理:订单查询、渠道管理、结算统计。5、关于数据统计:玩家排名、分区排名、渠道统计。6、程序是 .NE

下载
student_name course_name score row_num_rank rank_rank dense_rank_rank
张三 数学 95 1 1 1
王五 数学 95 2 1 1
李四 数学 90 3 3 2
赵六 数学 88 4 4 3
孙八 语文 85 1 1 1
周九 语文 85 2 1 1
钱七 语文 80 3 3 2
吴十 语文 78 4 4 3
郑一 英语 92 1 1 1
王二 英语 92 2 1 1
李三 英语 89 3 3 2

从表中可以清晰地看到,在“数学”和“英语”课程中,张三/王五(数学95分)和郑一/王二(英语92分)都是并列的,三种函数的行为差异一目了然。选择哪个函数,完全取决于你的业务逻辑对“并列”的定义和处理需求。

如何处理分组排名中的并列情况?

处理分组排名中的并列,实际上是根据业务需求选择合适的窗口函数,并在必要时加入额外的排序条件来“打破”并列。这不仅仅是技术实现问题,更是对业务逻辑的深入理解。

当我们遇到并列数据时,首先要明确业务上希望如何对待这些并列项:

  1. 所有并列项共享同一排名,且后续排名连续不跳跃:这正是
    DENSE_RANK()
    的适用场景。例如,我们想知道有多少个不同的分数等级,或者在不关心具体位次跳跃的情况下,给予并列者相同的“地位”。
  2. 所有并列项共享同一排名,但后续排名跳跃
    RANK()
    函数就是为此设计的。它模拟了许多传统排名系统,比如体育赛事中并列金牌后,银牌会直接从第三名开始。
  3. 即使并列也需要区分出唯一的排名:这时
    ROW_NUMBER()
    就派上用场了。但仅仅使用
    ROW_NUMBER() OVER (PARTITION BY ... ORDER BY score DESC)
    ,并列项的排名顺序是不确定的。为了让这个排名在并列时也具有确定性,我们需要在
    ORDER BY
    子句中添加一个额外的、能唯一区分行的列。

例如,如果“数学”课中有两个学生都考了95分,我们希望分数高的排前面,分数相同的情况下,

student_id
小的排前面。那么SQL可以这样写:

SELECT
    student_name,
    course_name,
    score,
    ROW_NUMBER() OVER (PARTITION BY course_name ORDER BY score DESC, student_id ASC) AS unique_rank_with_tie_breaker
FROM
    students_scores
ORDER BY
    course_name, score DESC, student_id ASC;

这里,

student_id ASC
作为第二个排序条件,在
score
相同的情况下,会根据
student_id
的大小来决定谁排在前面,从而确保
ROW_NUMBER()
给出的是一个完全确定的、唯一的排名。

选择哪种处理方式,取决于具体的业务规则。比如,在生成销售排行榜时,并列第一的销售额,可能更倾向于用

RANK()
来体现传统意义上的排名;但在做用户行为分析,需要找出每个用户在特定操作序列中的“第一个”或“最后一个”行为时,
ROW_NUMBER()
结合合适的
ORDER BY
会更精准。

分组排名在实际业务场景中有哪些应用?

分组排名远不止于学生成绩排名,它在各种业务场景中都扮演着关键角色,帮助我们从海量数据中提炼出有价值的洞察。它的应用场景非常广泛,几乎涵盖了所有需要“组内Top N”或“组内排序”的需求。

  1. 电商平台:找出每个商品类别中最畅销的Top 5商品。 这对于库存管理、商品推荐和市场营销策略至关重要。例如,

    SELECT * FROM (SELECT product_name, category, sales, ROW_NUMBER() OVER (PARTITION BY category ORDER BY sales DESC) AS rn FROM products) AS ranked_products WHERE rn <= 5;

  2. 金融风控:识别每个客户在过去一段时间内交易金额最大的Top 3交易。 这有助于分析客户行为模式,发现异常交易,或者评估客户价值。

  3. 网站分析:分析每个用户会话(session)中,用户访问的第一个页面和最后一个页面。 通过

    PARTITION BY session_id ORDER BY timestamp ASC
    ,可以轻松找出每个会话的起始和结束点,从而分析用户路径。

  4. 社交媒体:在每个话题标签下,找出最受欢迎的Top 10帖子。 这能帮助平台推荐热门内容,提升用户活跃度。

  5. 游戏行业:统计每个服务器中,玩家的等级排名。 或者找出每个公会中贡献值最高的成员,用于奖励和激励。

  6. 供应链管理:在每个仓库中,找出库存周转率最低的Top N商品。 这有助于优化库存结构,避免积压。

  7. 人力资源:统计每个部门员工的绩效排名。 辅助绩效评估和晋升决策。

这些例子都体现了分组排名的核心价值:将复杂的全局排序问题,分解为更易于管理和分析的局部排序问题。通过这种方式,我们能够更精细地理解数据,并根据特定分组的上下文做出决策,而不是泛泛地看待所有数据。可以说,只要你的数据存在“组”的概念,并且你需要在这个组内进行某种形式的排序或筛选,分组排名就是你不可或缺的工具。

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

683

2023.10.12

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

323

2023.10.27

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

348

2024.02.23

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

1096

2024.03.06

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

358

2024.03.06

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

697

2024.04.07

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

577

2024.04.29

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

418

2024.04.29

AO3中文版入口地址大全
AO3中文版入口地址大全

本专题整合了AO3中文版入口地址大全,阅读专题下面的的文章了解更多详细内容。

1

2026.01.21

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
SQL 教程
SQL 教程

共61课时 | 3.5万人学习

SQL优化与排查(MySQL版)
SQL优化与排查(MySQL版)

共26课时 | 2.3万人学习

MySQL索引优化解决方案
MySQL索引优化解决方案

共23课时 | 2.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号