使用mysql实现row_number() over(partition by col1 order by col2)函数

本文介绍如何使用MySQL通过自定义变量实现类似Oracle中的row_number()函数功能,以完成按部门分组并根据薪水进行排名的需求。提供了完整的SQL示例代码及执行结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[color=red]row_number() OVER (PARTITION BY COL1 ORDER BY COL2)[/color] 表示根据COL1分组,在分组内部根据 COL2排序,而此函数计算的


值就表示每组内部排序后的顺序编号(组内连续的唯一的).

是oracle的函数 我这里有个需求 就是把oracle转换成mysql语句

所以在网上找了一篇 解决方法 答案如下 可用到了用户变量 我晕了 不懂啊


求大虾们给解释啊

drop table if exists heyf_t10;
create table heyf_t10 (empid int ,deptid int ,salary decimal(10,2) );
insert into heyf_t10 values
(1,10,5500.00),
(2,10,4500.00),
(3,20,1900.00),
(4,20,4800.00),
(5,40,6500.00),
(6,40,14500.00),
(7,40,44500.00),
(8,50,6500.00),
(9,50,7500.00);
2. 确定需求: 根据部门来分组,显示各员工在部门里按薪水排名名次.
显示结果预期如下:
+-------+--------+----------+------+
| empid | deptid | salary | rank |
+-------+--------+----------+------+
| 1 | 10 | 5500.00 | 1 |
| 2 | 10 | 4500.00 | 2 |
| 4 | 20 | 4800.00 | 1 |
| 3 | 20 | 1900.00 | 2 |
| 7 | 40 | 44500.00 | 1 |
| 6 | 40 | 14500.00 | 2 |
| 5 | 40 | 6500.00 | 3 |
| 9 | 50 | 7500.00 | 1 |
| 8 | 50 | 6500.00 | 2 |
-----------------------------------------------

做好的sql,SQL 实现
[color=red]
select empid,deptid,salary,rank from (
select heyf_tmp.empid,heyf_tmp.deptid,heyf_tmp.salary,@rownum:=@rownum+1 ,
if(@pdept=heyf_tmp.deptid,@rank:=@rank+1,@rank:=1) as rank,
@pdept:=heyf_tmp.deptid
from (
select empid,deptid,salary from heyf_t10 order by deptid asc ,salary desc
) heyf_tmp ,
(select @rownum :=0 , @pdept := null ,@rank:=0) a
) result ;
[/color] 结果演示
+-------+--------+----------+------+
| empid | deptid | salary | rank |
+-------+--------+----------+------+
| 1 | 10 | 5500.00 | 1 |
| 2 | 10 | 4500.00 | 2 |
| 4 | 20 | 4800.00 | 1 |
| 3 | 20 | 1900.00 | 2 |
| 7 | 40 | 44500.00 | 1 |
| 6 | 40 | 14500.00 | 2 |
| 5 | 40 | 6500.00 | 3 |
| 9 | 50 | 7500.00 | 1 |
| 8 | 50 | 6500.00 | 2 |
+-------+--------+----------+------+
9 rows in set (0.00 sec)

-------------------------------------------------------
我的问题是
select heyf_tmp.empid,heyf_tmp.deptid,heyf_tmp.salary,@rownum:=@rownum+1 ,
if(@pdept=heyf_tmp.deptid,@rank:=@rank+1,@rank:=1) as rank,
@pdept:=heyf_tmp.deptid

这sql语句是先从右往左读 还是需哦那个左往右读啊??

是先执行的 @pdept:=heyf_tmp.deptid ,然后是if(@pdept=heyf_tmp.deptid,@rank:=@rank+1,@rank:=1) as rank,

再后是@rownum:=@rownum+1 ,吗?我理解的对吗??

还有 if(@pdept=heyf_tmp.deptid,@rank:=@rank+1,@rank:=1) 这句是什么意思啊 第一个表达式表达的是

如果@pdept等于heyf_tmp.deptid,然后执行第二个表达式,否则执行第三个表达式吗??
<think>嗯,用户问为什么使用ORDER BY f_date后查询结果出现了重复信息。首先,我需要确认用户对ORDER BY的理解是否正确。ORDER BY只是对结果进行排序,并不影响数据的唯一性,所以重复数据的存在应该和ORDER BY无关,而是原本数据中就存在的重复行。 接下来,考虑用户可能遇到的问题场景。用户可能在查询时没有使用DISTINCT或者GROUP BY,导致即使有ORDER BY,重复的数据依然被显示出来。这时候需要解释清楚ORDER BY的作用只是排序,并不会去重。 然后,需要分析可能的原因。比如,f_date字段本身可能有很多相同的日期,导致排序后这些相同日期的记录挨在一起,看起来像是重复。或者表中其他字段不同,但f_date相同,导致用户误以为是重复数据。 还需要考虑用户是否误解了重复数据的定义。比如,两条记录除了主键不同外,其他字段都相同,包括f_date,这时候虽然看起来重复,但实际上是不同的记录。这时候需要说明数据库中的唯一性通常由主键或唯一约束决定,而不是其他字段。 另外,可能用户的数据中存在真正的重复行,这时候需要建议用户检查数据,或者使用DISTINCT来去重。同时,提醒用户如果要去重,应该结合DISTINCT使用,而不是仅仅依靠ORDER BY。 还要注意不同数据库的差异,比如在某些情况下,如果没有指定排序方式,数据库可能返回不确定的顺序,但一旦用了ORDER BY,就会明确排序,可能让重复更明显。 最后,给出解决方案,比如使用DISTINCT、检查数据唯一性、添加唯一约束等,并举例说明如何正确去重和排序。同时,提醒用户理解排序和去重是两个不同的操作,需要根据需求选择合适的方法。</think>以下是关于 `ORDER BY f_date` 导致查询出现重复信息的详细分析及解决方案: --- ### **一、问题本质** `ORDER BY` **仅负责排序**,不会改变结果集的**数据内容**。若查询出现重复信息,说明原始数据中**本身存在重复记录**。以下分场景说明: --- ### **二、核心原因分析** #### **场景1:数据表本身存在重复记录** ```sql -- 示例数据 | id | name | f_date | |----|-------|--------------| | 1 | Alice | 2023-01-01 | | 2 | Bob | 2023-01-01 | -- f_date 相同但其他字段不同 | 3 | Alice | 2023-01-01 | -- 完全重复记录 ``` - **现象** 即使不使用 `ORDER BY`,直接 `SELECT * FROM table` 也会返回重复数据。 - **验证方法** ```sql SELECT COUNT(*) AS total, COUNT(DISTINCT id, name, f_date) AS unique_records FROM table; -- 若 total > unique_records,说明存在重复 ``` #### **场景2:未正确使用去重** ```sql -- 错误操作(未去重) SELECT name, f_date FROM table ORDER BY f_date; -- 可能输出: -- | Alice | 2023-01-01 | -- | Bob | 2023-01-01 | -- | Alice | 2023-01-01 | ``` - **解决方案** 明确是否需要去重: ```sql -- 去重操作 SELECT DISTINCT name, f_date FROM table ORDER BY f_date; ``` --- ### **三、特殊场景:隐式关联导致重复** #### **多表JOIN未正确关联** ```sql -- 错误示例(一对多关联) SELECT orders.order_id, users.name, orders.f_date FROM users JOIN orders ON users.id = orders.user_id ORDER BY f_date; -- 若一个用户有多个订单,会重复显示用户名 ``` - **解决方案** 明确业务需求: ```sql -- 方案1:接受重复(正常业务场景) -- 方案2:聚合统计(如统计订单数) SELECT users.name, COUNT(orders.order_id) AS order_count FROM users JOIN orders ON users.id = orders.user_id GROUP BY users.name ORDER BY order_count DESC; ``` --- ### **四、排查步骤** #### **步骤1:验证基础数据** ```sql -- 检查原始数据是否重复 SELECT f_date, COUNT(*) FROM table GROUP BY f_date HAVING COUNT(*) > 1; -- 列出有重复f_date的记录 ``` #### **步骤2:检查查询字段** ```sql -- 明确查询字段是否唯一 SELECT DISTINCT column1, column2... -- 检查哪些字段组合能唯一标识记录 ``` #### **步骤3:分析执行计划** ```sql EXPLAIN SELECT ... ORDER BY f_date; -- 查看是否涉及索引误用或全表扫描 ``` --- ### **五、解决方案** #### **方案1:明确是否需要去重** ```sql -- 使用 DISTINCT SELECT DISTINCT column1, column2 FROM table ORDER BY f_date; -- 使用 GROUP BY SELECT column1, MAX(column2) FROM table GROUP BY column1 ORDER BY f_date; ``` #### **方案2:添加唯一标识** ```sql -- 通过主键控制唯一性 SELECT * FROM table WHERE id IN ( SELECT MIN(id) FROM table GROUP BY duplicate_column ) ORDER BY f_date; ``` #### **方案3:重建唯一约束** ```sql -- 添加唯一索引(防止未来重复) ALTER TABLE table ADD UNIQUE INDEX idx_unique (col1, col2, f_date); ``` --- ### **六、易混淆概念** #### **误区:ORDER BY 会导致重复** - **正解**:`ORDER BY` 只是**排序触发器**,重复数据必须通过 `DISTINCT` 或 `GROUP BY` 处理。 #### **误区:时间字段天然唯一** - **正解**:除非特别设计,`f_date` 字段通常**允许重复**(如多用户在同一秒注册)。 --- ### **七、不同数据库的差异** | 数据库 | 特性 | |--------------|----------------------------------------------------------------------| | **MySQL** | 若无主键,`ORDER BY` 可能导致结果顺序不稳定 | | **PostgreSQL** | 支持 `DISTINCT ON (column)` 语法实现按指定字段去重 | | **SQL Server** | 可通过 `ROW_NUMBER() OVER (PARTITION BY ...)` 窗口函数去重 | --- ### **总结** 出现重复信息的根本原因是**数据本身存在重复**,与 `ORDER BY` 无关。应根据业务需求选择: - 接受重复(如需展示明细) - 使用 `DISTINCT`/`GROUP BY` 去重 - 修复数据源(添加唯一约束) 示例正确操作: ```sql -- 去重后按日期排序 SELECT DISTINCT name, f_date FROM employee ORDER BY f_date DESC; ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值