【mysql、sqlserver 4种分组排序函数dense_rank / row_number / rank / ntile】

本文介绍了SQL中常用的排序函数,包括row_number(), dense_rank(), rank() 和 ntile() 的使用方法及特点,并通过具体示例展示了如何在数据集中应用这些函数。

mysql高版本版本以上才支持函数(5.0+不支持),sqlserver原则上和mysql函数一致,以下截图来自sqlserver(2019)

--row_number()【概要:不考虑重复值】
--score的排序规则自然递增(不区分score重复)
select *,row_number() over(order by score desc) as 'row_number' from testuser;

 --以subject分组,组内score的排序规则自然顺序递增(不区分score相同情况)
select *,row_number() over(partition by subject order by score desc) as 'row_number' from testuser;

--dense_rank()【概要:考虑重复值,序号不间隔】
--score的排序规则递增(相同score序号一致,不同score需要自然递增,无序号间隔)
select *,dense_rank() over(order by score desc) as 'dense_rank' from testuser; 

--以subject分组,组内score的排序规则自然顺序递增(相同score序号一致,不同score需要自然递增,无序号间隔)
select *,dense_rank() over(partition by subject order by score desc) as 'dense_rank' from testuser;

--rank()【概要:考虑重复值,序号间隔】
--score的排序规则递增(相同score序号一致,不同score需要占位递增,序号存在间隔)
select *,rank() over(order by score desc) as 'rank' from testuser;

--以subject分组,组内score的排序规则自然顺序递增(相同score序号一致,不同score需要自然递增,存在序号间隔)
select *,rank() over(partition by subject order by score desc) as 'rank' from testuser;

--ntile()【概要:分组使用,区别于上面三种】
--按照排序规则分组,“ntile(3)”括号必须传值,分组数依托此参数
select *,ntile(4) over(order by score desc) as 'ntile' from testuser;

--先按照subject分组,如果分组数小于括号传值,则按照最小分组数
select *,ntile(4) over(partition by subject order by score desc) as 'ntile' from testuser;

 补充:

因为没找到自己满意的材料,自己整理发布,仅供参考,不喜勿喷

DDL语句:

DROP TABLE IF EXISTS `testuser`;
CREATE TABLE `testuser`  (
  `user_id` int NOT NULL AUTO_INCREMENT,
  `user_name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `score` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `subject` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`user_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;

DML语句:

INSERT INTO `sortFunction` (`user_id`, `user_name`, `score`, `subject`) VALUES (1, 'jame', '80', 'chinese');
INSERT INTO `sortFunction` (`user_id`, `user_name`, `score`, `subject`) VALUES (2, 'tom', '90', 'english');
INSERT INTO `sortFunction` (`user_id`, `user_name`, `score`, `subject`) VALUES (3, 'lucy', '80', 'english');
INSERT INTO `sortFunction` (`user_id`, `user_name`, `score`, `subject`) VALUES (4, 'kate', '70', 'psychology');
INSERT INTO `sortFunction` (`user_id`, `user_name`, `score`, `subject`) VALUES (5, 'jack', '70', 'psychology');
INSERT INTO `sortFunction` (`user_id`, `user_name`, `score`, `subject`) VALUES (6, 'tip', '60', 'psychology');

<think>好的,用户现在想了解SQL中的ROW_NUMBER()和RANK函数。我需要先回忆这两个函数的区别和用途,确保自己理解正确。 首先,ROW_NUMBER()是给每一行分配唯一的序号,即使有相同的排序值,序号也会递增。比如,如果有两个相同的分数,ROW_NUMBER()会根据ORDER BY的顺序给它们不同的行号。而RANK则是在有相同值时,会跳过后续的序号。比如两个并列第一,下一个就是第三名。 接下来,用户可能想知道这两个函数的典型应用场景。ROW_NUMBER()常用于分页或者去重,比如获取每个组的最高记录。而RANK适用于排名,比如学生成绩排名,允许并列名次。 还要注意它们的语法结构,包括PARTITION BY和ORDER BY子句的使用。可能需要举例说明,比如学生成绩表的例子,展示不同函数的结果差异。 用户可能对两者的区别不太清楚,特别是当处理相同值时的行为差异。需要强调ROW_NUMBER()不会出现重复序号,而RANK会。同时,DENSE_RANK也是一个相关函数,可以简单提及,但用户没有问,所以可能不需要深入。 另外,用户可能想知道在哪些数据库系统中支持这些函数。比如,SQL Server、Oracle、PostgreSQLMySQL 8.0+都支持。但可能需要确认,不过用户的问题比较通用,可能不需要涉及具体数据库的差异。 最后,需要总结使用场景,帮助用户根据需求选择合适的函数。确保回答结构清晰,分点说明,并用例子辅助理解。还要检查是否有常见的误区,比如嵌套使用或性能问题,但用户的问题比较基础,可能不需要深入这部分。</think>好的,以下是关于 SQL 中 `ROW_NUMBER()` 和 `RANK()` 函数的对比说明,结合示例帮助理解它们的区别和用途: --- ### 1. **基本概念** #### (1) **ROW_NUMBER()** - **功能**:为查询结果的每一行分配**唯一序号**(即使排序字段值相同,序号也不同)。 - **特点**:严格按 `ORDER BY` 顺序生成连续序号,**无重复值**。 - **语法**: ```sql ROW_NUMBER() OVER ( [PARTITION BY 分组字段] ORDER BY 排序字段 [ASC/DESC] ) ``` #### (2) **RANK()** - **功能**:为数据分配**跳跃式排名**(相同值的行排名相同,后续排名跳过重复值的数量)。 - **特点**:允许并列排名,但后续排名会出现空缺。 - **语法**: ```sql RANK() OVER ( [PARTITION BY 分组字段] ORDER BY 排序字段 [ASC/DESC] ) ``` --- ### 2. **示例对比** 假设有一个学生成绩表 `scores`: | 学生姓名 | 分数 | |----------|------| | 张三 | 90 | | 李四 | 85 | | 王五 | 90 | | 赵六 | 80 | 执行以下查询: ```sql SELECT 学生姓名, 分数, ROW_NUMBER() OVER (ORDER BY 分数 DESC) AS row_num, RANK() OVER (ORDER BY 分数 DESC) AS rank_num FROM scores; ``` **结果**: | 学生姓名 | 分数 | row_num | rank_num | |----------|------|---------|----------| | 张三 | 90 | 1 | 1 | | 王五 | 90 | 2 | 1 | | 李四 | 85 | 3 | 3 | | 赵六 | 80 | 4 | 4 | **关键差异**: - `ROW_NUMBER()`:即使张三和王五分数相同,仍分配不同序号(1 和 2)。 - `RANK()`:张三和王五并列第 1 名,李四直接跳到第 3 名(空缺第 2 名)。 --- ### 3. **典型应用场景** #### (1) **ROW_NUMBER()** - **分页查询**:配合 `WHERE row_num BETWEEN N AND M` 实现分页。 - **去重取唯一记录**:结合 `PARTITION BY` 分组后取每组第一行: ```sql SELECT * FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY 部门 ORDER BY 入职时间 DESC) AS rn FROM employees ) t WHERE rn = 1; -- 取每个部门最新入职的员工 ``` #### (2) **RANK()** - **允许并列的排名**:如比赛成绩排名、销售业绩排名。 - **统计跳跃式名次**: ```sql SELECT * FROM ( SELECT 产品名称, 销售额, RANK() OVER (ORDER BY 销售额 DESC) AS 排名 FROM products ) t WHERE 排名 <= 3; -- 获取销售额前三名(允许并列) ``` --- ### 4. **对比其他函数** - **DENSE_RANK()**:与 `RANK()` 类似,但排名连续不跳跃(例如,张三和王五并列第 1,李四仍为第 2 名)。 - **NTILE(n)**:将数据分为 `n` 个桶(如划分前 10%、中间 80%、后 10%)。 --- ### 5. **注意事项** - **性能影响**:窗口函数可能增加查询复杂度,大数据量时需优化索引。 - **数据库兼容性**:多数现代数据库(如 SQL Server、Oracle、PostgreSQLMySQL 8.0+)均支持。 --- ### 总结 - 需要**唯一序号**且不关心并列时 → `ROW_NUMBER()`。 - 需要**允许并列且有跳跃排名**时 → `RANK()`。 - 需要**允许并列且连续排名**时 → `DENSE_RANK()`。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值