为什么我们不能使用rank()分析函数来删除表中的重复项?

时间:2014-11-30 09:05:18

标签: sql oracle

我创建了一个包含以下记录的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

当我使用内部查询来获取表中所有结果的rownumbers时,它给出了以下结果:

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?

2 个答案:

答案 0 :(得分:3)

这就是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 |
+---+------------+------+------------+

答案 1 :(得分:2)

有三种“排名”分析函数:row_number()rank()dense_rank()

这些都非常相似。它们按顺序将数字分配给组内的行。该组由partition by子句定义。排序由order by子句定义。三者之间的区别在于它们如何处理重复值。

row_number() 始终返回组内的序号。当存在联系时,等值行具有连续值,但它们是不同的。

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