为啥我们不能使用 rank() 分析函数来删除表中的重复项?
Posted
技术标签:
【中文标题】为啥我们不能使用 rank() 分析函数来删除表中的重复项?【英文标题】:Why cant we use rank() analytic function to delete duplicates in a table?为什么我们不能使用 rank() 分析函数来删除表中的重复项? 【发布时间】:2014-11-30 09:05:18 【问题描述】:我创建了一个 emp 表,其中包含以下记录。
create table emp(
EMPNO integer,
EMPNAME varchar2(20),
SALARY number);
select * from emp;
empno empname salary
10 bill 2000
11 bill 2000
12 mark 3000
12 mark 3000
12 mark 3000
12 philip 3000
12 john 3000
13 tom 4000
14 tom 4000
14 jerry 5000
14 matt 5000
15 susan 5000
为了删除重复项,我一直在使用 rownum() 函数以及 partition by 和 order by 子句,查询如下:
delete from emp where rowid in
(
select rid from
(
select rowid rid,
row_number() over(partition by empno order by empno) rn
from emp
)
where rn > 1
);
--6 rows deleted
该查询删除了所有具有重复 empno 的员工记录,结果如下所示:
empno empname salary
10 bill 2000
11 bill 2000
12 mark 3000
13 tom 4000
14 tom 4000
15 susan 5000
当我使用内部查询来获取表中所有结果的行号时,它会给我以下结果:
select rowid as rid,empno,empname,
row_number() over(partition by empno order by empno) rn
from emp;
rowid rownumber
AACDJUAAPAAGLlTAAA 10 bill 1
AACDJUAAPAAGLlTAAB 11 bill 1
AACDJUAAPAAGLlTAAE 12 mark 1
AACDJUAAPAAGLlTAAD 12 mark 2
AACDJUAAPAAGLlTAAC 12 mark 3
AACDJUAAPAAGLlTAAF 12 philip 4
AACDJUAAPAAGLlTAAG 12 john 5
AACDJUAAPAAGLlTAAH 13 tom 1
AACDJUAAPAAGLlTAAI 14 tom 1
AACDJUAAPAAGLlTAAJ 14 jerry 2
AACDJUAAPAAGLlTAAK 14 matt 3
AACDJUAAPAAGLlTAAL 15 susan 1
但是当我使用 rank() 代替 rownumber() 函数时,它给了我以下结果:
select rowid as rid,empno,empname,
rank() over(partition by empno order by empno) rn
from emp;
rowid rank
AACDJUAAPAAGLlTAAA 10 bill 1
AACDJUAAPAAGLlTAAB 11 bill 1
AACDJUAAPAAGLlTAAE 12 mark 1
AACDJUAAPAAGLlTAAD 12 mark 1
AACDJUAAPAAGLlTAAC 12 mark 1
AACDJUAAPAAGLlTAAF 12 philip 1
AACDJUAAPAAGLlTAAG 12 john 1
AACDJUAAPAAGLlTAAH 13 tom 1
AACDJUAAPAAGLlTAAI 14 tom 1
AACDJUAAPAAGLlTAAJ 14 jerry 1
AACDJUAAPAAGLlTAAK 14 matt 1
AACDJUAAPAAGLlTAAL 15 susan 1
所以我的问题是,为什么 rank() 为表中的所有记录赋予相同的值,即使有重复的 empid?
【问题讨论】:
根据您的业务规则,"a duplicate" 到底是什么:(1) 相同 id (2) 相同名称 (3) 相同 id 和 同名? 【参考方案1】:RANK()
就是这样工作的。为分区内的相同排名的行获得不同的RANK
值将是相当令人惊讶的。事实上,ORDER BY
子句是分区内RANK
的重要驱动因素,但是由于您对分区使用与排序相同的列,因此很明显,每一行在各自的分区中排名第一(因为它们是分区中唯一的值)
See an explanation in this blog post,这里的 SQL(PostgreSQL 语法)
SELECT
v,
ROW_NUMBER() OVER (window) row_number,
RANK() OVER (window) rank,
DENSE_RANK() OVER (window) dense_rank
FROM t
WINDOW window AS (ORDER BY v)
ORDER BY v
...产生这个输出
+---+------------+------+------------+
| V | ROW_NUMBER | RANK | DENSE_RANK |
+---+------------+------+------------+
| a | 1 | 1 | 1 |
| a | 2 | 1 | 1 |
| a | 3 | 1 | 1 |
| b | 4 | 4 | 2 |
| c | 5 | 5 | 3 |
| c | 6 | 5 | 3 |
| d | 7 | 7 | 4 |
| e | 8 | 8 | 5 |
+---+------------+------+------------+
【讨论】:
知道了,但在我的示例中,为什么 rank() 没有增加?...我的意思是为什么它没有将 empno 11 的排名分配为“2”?...是因为我正在分区通过empno? @abhi1489 只有一个员工的empno=11,所以他在他的团队中排名第一。 @abhi1489,很抱歉,我没有从你的问题中听到那部分。是的,empno=11
在他们的分区中排名第一。你写查询的方式,其实每个人都在自己的分区中排名第一。【参考方案2】:
共有三个“排名”分析函数:row_number()
、rank()
和 dense_rank()
。
这些都非常相似。他们按顺序为组内的行分配编号。该组由partition by
子句定义。排序由order by
子句定义。三者之间的区别在于它们处理重复值的方式。
row_number()
always 返回组内的序号。当存在平局时,相等值的行具有顺序值,但它们是不同的。
dense_rank()
分配没有间隙的连续值。但是,相等值的行被赋予相同的值。下一个值的排名再高。
rank()
分配有间隔的连续值。等值的行具有相同的值,但后续行有一个间隙。
这是一个例子:
value row_number dense_rank rank
a 1 1 1
b 2 2 2
b 3 2 2
b 4 2 2
c 5 3 5
d 6 4 6
d 7 4 6
【讨论】:
以上是关于为啥我们不能使用 rank() 分析函数来删除表中的重复项?的主要内容,如果未能解决你的问题,请参考以下文章
[转]oracle分析函数Rank, Dense_rank, row_number
oracle的row_number()over rank()over和dense_rank()over这三种分析函数(转)