使用ROWNUM删除重复记录?

时间:2018-09-22 19:52:43

标签: sql oracle

我知道如何使用ROWID删除重复的记录。

请指导我在Oracle中使用ROWNUM删除重复的记录。

1 个答案:

答案 0 :(得分:0)

那是行不通的。来自documentation

  

对于查询返回的每一行,ROWNUM伪列返回一个数字,该数字指示Oracle从表或连接的行集中选择行的顺序。所选的第一行的ROWNUM为1,第二行的为2,依此类推。

它的值是在运行查询时设置的,可以根据获取数据的方式 进行更改(不同的ORDER BY会产生不同的ROWNUM值同一行)。由于它是顺序的,因此您无法设置ROWNUM值的“组”(例如,它从一组的1、2、3到另一组的1、2、3、4、5, -您将始终获得1,2,3,4,5,6,7,8)。

如果您打算执行以下操作:

SQL> create table test as
  2    select e.empno, e.deptno, d.dname, e.ename
  3    from emp e join dept d on e.deptno = d.deptno;

Table created.

SQL> select * from test order by deptno;

     EMPNO     DEPTNO DNAME          ENAME
---------- ---------- -------------- ----------
      7782         10 ACCOUNTING     CLARK
      7839         10 ACCOUNTING     KING
      7934         10 ACCOUNTING     MILLER
      7369         20 RESEARCH       SMITH
      7902         20 RESEARCH       FORD
      7566         20 RESEARCH       JONES
      7900         30 SALES          JAMES
      7844         30 SALES          TURNER
      7654         30 SALES          MARTIN
      7521         30 SALES          WARD
      7499         30 SALES          ALLEN
      7698         30 SALES          BLAKE

12 rows selected.

SQL> delete from test t
  2  where t.empno in (select a.empno
  3                    from (select t1.empno, t1.deptno, t1.dname, rownum rn
  4                          from test t1
  5                         ) a
  6                    where a.rn > 1
  7                   );

11 rows deleted.

如您所见,所有行(但只有一行)是重复的。原因如下:

SQL> rollback;

Rollback complete.

SQL> select a.deptno, a.empno, a.rn, a.rn1
  2  from (select t1.empno, t1.deptno, t1.dname, rownum rn,
  3               row_number() over (partition by t1.deptno order by null) rn1
  4        from test t1
  5       ) a;

    DEPTNO      EMPNO         RN        RN1
---------- ---------- ---------- ----------
        10       7782          2          1
        10       7839          1          2
        10       7934          3          3
        20       7369          5          1
        20       7902          4          2
        20       7566          6          3
        30       7900          7          1
        30       7844          8          2
        30       7654          9          3
        30       7521         10          4
        30       7499         11          5
        30       7698         12          6

12 rows selected.

看到了吗? RN(ROWNUM)的所有值分别为1、2,...,12。RN1(ROW_NUMBER,允许我们设置分区)可以正确完成工作。因此,如果您使用RN1而不是RN,则可以使用:

SQL> delete from test t
  2  where t.empno in (select a.empno
  3                    from (select t1.empno, t1.deptno, t1.dname, rownum rn,
  4                          row_number() over (partition by t1.deptno order by null) rn1
  5                          from test t1
  6                         ) a
  7                    where a.rn1 > 1
  8                   );

9 rows deleted.

SQL> select * From test;

     EMPNO     DEPTNO DNAME          ENAME
---------- ---------- -------------- ----------
      7782         10 ACCOUNTING     CLARK
      7369         20 RESEARCH       SMITH
      7900         30 SALES          JAMES

SQL>

[编辑:删除重复的#2]

这是另一个示例,该示例显示了要删除重复项时的操作方式。它基于“ ROWID技术”(尽管也有其他方法)。

回到我们一直在使用的表。假设我们只希望每个部门保留一份不同的工作:

SQL> select deptno, job, dname, empno, ename
  2  from test
  3  order by deptno, job;

    DEPTNO JOB       DNAME               EMPNO ENAME
---------- --------- -------------- ---------- ----------
        10 CLERK     ACCOUNTING           7934 MILLER
        10 MANAGER   ACCOUNTING           7782 CLARK
        10 PRESIDENT ACCOUNTING           7839 KING

        20 ANALYST   RESEARCH             7902 FORD
        20 CLERK     RESEARCH             7369 SMITH
        20 MANAGER   RESEARCH             7566 JONES

        30 CLERK     SALES                7900 JAMES
        30 MANAGER   SALES                7698 BLAKE
        30 SALESMAN  SALES                7844 TURNER    -- leave
        30 SALESMAN  SALES                7654 MARTIN    -- only
        30 SALESMAN  SALES                7521 WARD      -- one
        30 SALESMAN  SALES                7499 ALLEN     -- salesman

12 rows selected.
  • 在部门10中,没有重复项-3名员工,每个人都做自己的工作
  • 第20部门也是如此
  • 但是,在第30部门中,有4个推销员,我们只想保留一个-另一个是重复

这意味着删除行时必须同时考虑DEPTNO和JOB两列。让我们做到这一点:

SQL> delete from test a
  2  where rowid > (select min(rowid)
  3                 from test b
  4                 where a.deptno = b.deptno  --> take both DEPTNO ...
  5                   and a.job = b.job        --> and JOB into account
  6                );

3 rows deleted.

结果:第10部门和第20部门没有变化,但是在第30部门中,我们只有一名推销员,就像我们想要的那样:

SQL> select deptno, job, dname, empno, ename
  2  from test
  3  order by deptno, job;

    DEPTNO JOB       DNAME               EMPNO ENAME
---------- --------- -------------- ---------- ----------
        10 CLERK     ACCOUNTING           7934 MILLER
        10 MANAGER   ACCOUNTING           7782 CLARK
        10 PRESIDENT ACCOUNTING           7839 KING
        20 ANALYST   RESEARCH             7902 FORD
        20 CLERK     RESEARCH             7369 SMITH
        20 MANAGER   RESEARCH             7566 JONES
        30 CLERK     SALES                7900 JAMES
        30 MANAGER   SALES                7698 BLAKE
        30 SALESMAN  SALES                7844 TURNER

9 rows selected.

SQL>