如何利用SQL JOIN连接实现复杂的排名(Rank)或行号计算?

雨浩吖_6580

雨浩吖_6580

2026-06-20

864人浏览

原创

sql中无窗口函数时,可通过自连接或相关子查询模拟rank()和row_number():对每行统计排序更优的记录数加1,rank()用严格比较,row_number()需加唯一键区分;分组排名用left join+group by;dense_rank()用count(distinct);性能依赖索引,优先使用窗口函数。

如何利用sql join连接实现复杂的排名(rank)或行号计算?

SQL 中没有窗口函数时怎么实现 RANK() 或 ROW_NUMBER()

MySQL 5.7 或更早版本、SQLite(默认不支持)、某些嵌套子查询受限的 OLAP 场景下,RANK() 和 ROW_NUMBER() 直接不可用。必须靠自连接或相关子查询模拟。

核心思路是:对每条记录,统计“排序条件更优”的记录数量,再加 1。比如按 score 降序排名,就数有多少条 score > 当前行 score 的记录。

  • 写法示例(MySQL 5.7):
    SELECT a.name, a.score,
           (SELECT COUNT(*) + 1 FROM students b WHERE b.score > a.score) AS rank_num
    FROM students a
    ORDER BY a.score DESC;
  • 注意 b.score > a.score 是严格大于,所以并列分数会得到相同排名(模拟 RANK());若要 ROW_NUMBER() 效果,需额外加唯一键比较,如 b.score > a.score OR (b.score = a.score AND b.id
  • 性能极差:子查询对每行都全表扫描,10k 行可能触发 O(n²) 复杂度,线上环境慎用

JOIN 实现多字段分组内排名(如每个部门按薪资排名)

单纯用子查询难处理“分组内排名”,因为需要限制统计范围。这时 JOIN 更可控——先 JOIN 出同组所有记录对,再聚合计数。

关键点在于 JOIN 条件既要限定分组(a.dept = b.dept),又要表达排序逻辑(b.salary > a.salary)。

  • 示例(部门内薪资降序排名):
    SELECT a.name, a.dept, a.salary,
           COUNT(b.salary) + 1 AS dept_rank
    FROM employees a
    LEFT JOIN employees b ON a.dept = b.dept AND b.salary > a.salary
    GROUP BY a.name, a.dept, a.salary
    ORDER BY a.dept, a.salary DESC;
  • LEFT JOIN 保证即使最高薪员工(没人比他高)也能保留,COUNT(b.salary) 对空匹配返回 0,+1 后得 1
  • 如果存在薪资相同的人,此写法会给出相同排名(即 RANK() 行为);要 DENSE_RANK() 需改用 COUNT(DISTINCT b.salary)
  • 注意:JOIN 字段必须有索引,否则 a.dept = b.dept AND b.salary > a.salary 无法走联合索引,性能雪崩

MySQL 8.0+ 或 PostgreSQL 中 JOIN 和窗口函数混用的典型误用

有人试图在已有窗口函数的环境下,还硬套 JOIN 实现排名,结果反而出错或低效。

女娲.skill
女娲.skill

女娲.skill是一款AI开发辅助工具,独立开发者花叔开源的 SKill 项目。

下载

常见错误包括:在 OVER(PARTITION BY ...) 已能解决分组排名时,仍写冗余 JOIN;或在窗口函数结果上再 JOIN 做二次计算,引发重复行或 NULL。

  • 正确做法:优先用 ROW_NUMBER() OVER(PARTITION BY dept ORDER BY salary DESC),它比 JOIN 快一个数量级,且语义清晰
  • JOIN 仅在以下情况必要:需同时引用排名前/后行的其他字段(如“上一名的姓名”),而窗口函数的 LAG()/LEAD() 不够用时
  • 危险组合:SELECT *, ROW_NUMBER() OVER(...) AS rnk FROM t1 JOIN t2 ON ... —— 若 JOIN 导致主表行膨胀,ROW_NUMBER() 会在膨胀后的结果集上计算,不是你想要的“原表内排名”

PostgreSQL 中用 LATERAL JOIN 模拟动态排名条件

当排名逻辑依赖运行时参数(比如用户传入的基准分、动态权重),普通窗口函数写死,而 JOIN 可结合 LATERAL 灵活构造。

LATERAL 允许右侧子查询引用左侧列,适合把“每行的排名基准”作为变量传入。

  • 示例:对每个学生,计算其分数超过班级平均分多少分,并按该差值排名
    SELECT s.name, s.score - avg_score.avg AS diff,
           ROW_NUMBER() OVER (ORDER BY s.score - avg_score.avg DESC) AS rank_by_diff
    FROM students s,
    LATERAL (SELECT AVG(score) AS avg FROM students WHERE class_id = s.class_id) AS avg_score;
  • 注意逗号 JOIN 是 PostgreSQL 对 CROSS JOIN LATERAL 的简写,等价于显式写 CROSS JOIN LATERAL
  • 不能用普通 JOIN 替代:因为 AVG(score) 需按 s.class_id 动态分组,普通 JOIN 无法关联到当前行的 class_id
  • LATERAL 子查询执行次数 = 左侧行数,若 avg_score 查询未命中索引,同样会慢

实际用 JOIN 做排名,本质是在弥补窗口函数缺失或应对动态条件。但只要数据库支持标准窗口函数,就别绕路——JOIN 排名是退路,不是首选。真正容易被忽略的,是 JOIN 条件里那个隐含的索引需求:没索引,再正确的逻辑也会在 10 万行时卡死。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

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

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

2023.10.12

3823

8

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

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

2023.10.27

811

4

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

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

2024.02.23

989

5

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

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

2024.03.06

5641

10

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

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

2024.03.06

2603

4

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

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

2024.04.07

5620

11

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

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

2024.04.29

7381

6

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

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

2024.04.29

1010

5

sql中删除一列的命令是什么
sql中删除一列的命令是什么

在sql中,使用alter table语句可以删除一列,语法为:alter table table_name drop column column_name。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

872

5

热门下载

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

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.6万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.2万人学习