使用pl / sql在表中查找重复的行

时间:2018-02-13 16:48:20

标签: oracle plsql

我试图创建函数,块或过程,以在表中找到重复的行(而不是在两个表之间)。我在Oracle“emp”中使用了默认表,当然我复制了一行,以查看结果。这是我的代码而我还没有成功

 declare
  cursor c1 is select * from emp;
  cursor c2 is select * from emp;

  V_REGISTERS c1%rowtype;
  V_REGISTERS2 c2%rowtype;

  BEGIN
   <<OUTER>>
    FOR V_REGISTERS IN c1
      LOOP
        FOR V_REGISTERS2 IN c2

          LOOP
          IF (
              V_REGISTERS.EMPNO=V_REGISTERS2.EMPNO AND
              V_REGISTERS.ENAME=V_REGISTERS2.ENAME AND
              V_REGISTERS.JOB=V_REGISTERS2.JOB AND
              V_REGISTERS.MGR = V_REGISTERS2.MGR AND
              V_REGISTERS.HIREDATE=V_REGISTERS2.HIREDATE AND
              V_REGISTERS.SAL=V_REGISTERS2.SAL AND
              V_REGISTERS.COMM=V_REGISTERS2.COMM AND
              V_REGISTERS.DEPTNO=V_REGISTERS2.DEPTNO

              ) 


             THEN


                dbms_output.put_line('I HAVE FOUND THE REPEATED ROWS');
                dbms_output.put_line(to_char(V_REGISTERS.empno) ||' '|| V_REGISTERS.ename ||' '|| V_REGISTERS.job ||' '|| to_char(V_REGISTERS.mgr) ||' '|| to_char(V_REGISTERS.hiredate)||' '||
                to_char(V_REGISTERS.sal)||' '|| to_char(V_REGISTERS.comm)||' '|| to_char(V_REGISTERS.deptno));

                dbms_output.put_line(to_char(V_REGISTERS2.empno) ||' '|| V_REGISTERS2.ename ||' '|| V_REGISTERS2.job ||' '|| to_char(V_REGISTERS2.mgr) ||' '|| to_char(V_REGISTERS2.hiredate)||' '||
                to_char(V_REGISTERS2.sal)||' '|| to_char(V_REGISTERS2.comm)||' '|| to_char(V_REGISTERS2.deptno));
                dbms_output.put_line('  ');
                dbms_output.put_line('  ');

          END IF;

          END LOOP;
      END LOOP OUTER;
  END;

我完全了解使用动态函数,并丢弃pl / sql,就像这样......

 select * 
  from (
    select f.*, 
    count(*) over (partition by empno,ename,job) ct
    from   emp f
  )
  where  ct > 1

......得到......

7698    BLAKE   MANAGER 7839    01/05/81    2850        30  2
7698    BLAKE   MANAGER 7839    01/05/81    2850        30  2

..但这不是我的目标。

任何帮助或建议,都会非常感激。感谢

4 个答案:

答案 0 :(得分:1)

你试图做的循环也检查相同的记录,所以即使它有一个记录它会显示为重复..我修改你的游标得到rownum和条件不匹配相同的rownum在循环可能会给你正确的输出。

我做了以下。在创建表并插入重复记录后,我运行了脚本并返回了重复的记录。

create table emp
(empno number,
ename varchar2(10),
job varchar2(10),
mgr varchar2(10),
hiredate date,
sal number,
comm number,
deptno number);

insert into emp
values
(
7698,    'BLAKE', 'ASSISTANT',  'JERRY',to_date('14/02/2018','dd/mm/yyyy'), 7839,     2850,        30);
insert into emp
values
(
7698,    'BLAKE', 'ASSISTANT',  'JERRY',to_date('14/02/2018','dd/mm/yyyy'), 7839,     2850,        30);
insert into emp
values
(
7698,    'DAN', 'ANALYST',  'TOM',to_date('14/02/2018','dd/mm/yyyy'), 7839,     2850,        30);


declare
  cursor c1 is select EMP.*,ROWNUM from emp ORDER BY EMPNO DESC;
  cursor c2 is select EMP.*,ROWNUM from emp  ORDER BY EMPNO DESC;

  V_REGISTERS c1%rowtype;
  V_REGISTERS2 c2%rowtype;

  BEGIN
   <<OUTER>>
    FOR V_REGISTERS IN c1
      LOOP
        FOR V_REGISTERS2 IN c2

          LOOP
          IF (
              V_REGISTERS.EMPNO=V_REGISTERS2.EMPNO AND
              V_REGISTERS.ENAME=V_REGISTERS2.ENAME AND
              V_REGISTERS.JOB=V_REGISTERS2.JOB AND
              V_REGISTERS.MGR = V_REGISTERS2.MGR AND
              V_REGISTERS.HIREDATE=V_REGISTERS2.HIREDATE AND
              V_REGISTERS.SAL=V_REGISTERS2.SAL AND
              V_REGISTERS.COMM=V_REGISTERS2.COMM AND
              V_REGISTERS.DEPTNO=V_REGISTERS2.DEPTNO AND
              V_REGISTERS.ROWNUM <> V_REGISTERS2.ROWNUM

              ) 


             THEN


                dbms_output.put_line('I HAVE FOUND THE REPEATED ROWS');
                dbms_output.put_line(to_char(V_REGISTERS.empno) ||' '|| V_REGISTERS.ename ||' '|| V_REGISTERS.job ||' '|| to_char(V_REGISTERS.mgr) ||' '|| to_char(V_REGISTERS.hiredate)||' '||
                to_char(V_REGISTERS.sal)||' '|| to_char(V_REGISTERS.comm)||' '|| to_char(V_REGISTERS.deptno));

                dbms_output.put_line(to_char(V_REGISTERS2.empno) ||' '|| V_REGISTERS2.ename ||' '|| V_REGISTERS2.job ||' '|| to_char(V_REGISTERS2.mgr) ||' '|| to_char(V_REGISTERS2.hiredate)||' '||
                to_char(V_REGISTERS2.sal)||' '|| to_char(V_REGISTERS2.comm)||' '|| to_char(V_REGISTERS2.deptno));
                dbms_output.put_line('  ');
                dbms_output.put_line('  ');

          END IF;

          END LOOP;
      END LOOP OUTER;
  END;

输出:

我已经找到了重复的行

7698 BLAKE ASSISTANT JERRY 14-FEB-18 7839 2850 30

7698 BLAKE ASSISTANT JERRY 14-FEB-18 7839 2850 30

我已经找到了重复的行

7698 BLAKE ASSISTANT JERRY 14-FEB-18 7839 2850 30

7698 BLAKE ASSISTANT JERRY 14-FEB-18 7839 2850 30

答案 1 :(得分:1)

您可以使用GROUP BY功能,如下所示:

.gitignore

答案 2 :(得分:0)

这是一种只用一个光标和一个表格传递的方法。我们简单地记住前一行是什么,并将其与当前行进行比较。即使有很多,“l_in_a_dup_list”也只打印出1次重复,但如果你想要所有的重复,那么很容易删除。

SQL> create table t as select * from scott.emp;

Table created.

SQL> insert into t select * from scott.emp where rownum <= 2;

2 rows created.

SQL> insert into t select * from scott.emp where rownum <= 2;

2 rows created.

SQL> insert into t select * from scott.emp where rownum <= 2;

2 rows created.

SQL>
SQL> set serverout on
SQL> declare
  2    --
  3    -- we'll assume that empno/ename/hiredate is the definition of duplicate here
  4    -- but it could be anything (including all columns)
  5    --
  6    l_this_key varchar2(4000);
  7    l_prev_key varchar2(4000) := '<nothing yet>';
  8    l_in_a_dup_list  boolean := false;
  9  begin
 10    for i in (
 11      select * from t
 12      order by empno, ename, hiredate
 13      )
 14    loop
 15      l_this_key := i. empno||'-'||i.ename||'-'||to_char(i.hiredate,'yyyymmddhh24miss');
 16      if l_this_key = l_prev_key
 17      then
 18         if not l_in_a_dup_list then
 19           dbms_output.put_line(l_this_key||' is a duplicate');
 20           l_in_a_dup_list := true;
 21         end if;
 22      else
 23         l_in_a_dup_list := false;
 24      end if;
 25      l_prev_key := l_this_key;
 26    end loop;
 27  end;
 28  /
7369-SMITH-19801217000000 is a duplicate
7499-ALLEN-19810220000000 is a duplicate

PL/SQL procedure successfully completed.

答案 3 :(得分:0)

只需使用分析功能。 RANK()似乎最适合这里。

SELECT 列列表,以逗号分隔 FROM( 选择 RANK()OVER(由列分隔,由逗号分隔 ORDER BY RowIdentifier )RNK,* 来自EMP )RNK RNK.RNK&gt; 1

此查询将对表中的行进行分区并为其提供排名。例如,如果第3条记录和第5条记录在RANK()函数的分区子句中提到的那些列中具有相同的数据,那么它将第3行排名为1,第5行排名为2,因此在外部查询中如果你已经过滤了超过1的等级,你将获得所有重复的记录,如果你过滤了rank = 1,你将获得没有重复的独特记录。

谢谢☺