web-dev-qa-db-ja.com

Oracleのテーブルから重複行を削除する

Oracleで何かをテストし、テーブルにサンプルデータを追加しましたが、その過程で誤って重複レコードをロードしたため、列の一部を使用して主キーを作成できません。

重複する行をすべて削除して、そのうちの1つだけを残すにはどうすればよいですか?

126
juan

rowid疑似列を使用します。

DELETE FROM your_table
WHERE rowid not in
(SELECT MIN(rowid)
FROM your_table
GROUP BY column1, column2, column3);

column1column2、およびcolumn3は、各レコードの識別キーを構成します。すべての列をリストできます。

259
Bill the Lizard

From Ask Tom

delete from t
 where rowid IN ( select rid
                    from (select rowid rid, 
                                 row_number() over (partition by 
                         companyid, agentid, class , status, terminationdate
                                   order by rowid) rn
                            from t)
                   where rn <> 1);

(欠落している括弧を修正)

15
Dead Programmer
DELETE FROM tablename a
      WHERE a.ROWID > ANY (SELECT b.ROWID
                             FROM tablename b
                            WHERE a.fieldname = b.fieldname
                              AND a.fieldname2 = b.fieldname2)
11
user187624

DevX.com から:

DELETE FROM our_table
WHERE rowid not in
(SELECT MIN(rowid)
FROM our_table
GROUP BY column1, column2, column3...) ;

Column1、column2などは、使用するキーです。

11
Mark

解決策1)

delete from emp
where rowid not in
(select max(rowid) from emp group by empno);

解決策2)

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
               );

解決策3)

delete from emp e1
         where rowid not in
          (select max(rowid) from emp e2
           where e1.empno = e2.empno ); 
7
DoOrDie

t1とは異なる*を選択してテーブルt2を作成します。

6
Mohammed khaled

重複を選択するには、クエリ形式のみを使用できます。

SELECT GroupFunction(column1), GroupFunction(column2),..., 
COUNT(column1), column1, column2...
FROM our_table
GROUP BY column1, column2, column3...
HAVING COUNT(column1) > 1

したがって、他の提案による正しいクエリは次のとおりです。

DELETE FROM tablename a
      WHERE a.ROWID > ANY (SELECT b.ROWID
                             FROM tablename b
                            WHERE a.fieldname = b.fieldname
                              AND a.fieldname2 = b.fieldname2
                              AND ....so on.. to identify the duplicate rows....)

このクエリは、WHERE CLAUSEで選択された基準について、データベース内の最も古いレコードを保持します。

Oracle認定アソシエイト(2008)

3
user1799846

ループのカーソルを使用して小さなpl/sqlブロックを実行し、保持したくない行を削除する必要があります。例えば:

declare
prev_var my_table.var1%TYPE;

begin

for t in (select var1 from my_table order by var 1) LOOP

-- if previous var equal current var, delete the row, else keep on going.
end loop;

end;
3
Nick
DELETE from table_name where rowid not in (select min(rowid) FROM table_name group by column_name);

また、別の方法で重複レコードを削除することもできます

DELETE from table_name a where rowid > (select min(rowid) FROM table_name b where a.column=b.column);
2
Md Wasi
create table abcd(id number(10),name varchar2(20))

insert into abcd values(1,'abc')

insert into abcd values(2,'pqr')


insert into abcd values(3,'xyz')

insert into abcd values(1,'abc')

insert into abcd values(2,'pqr')

insert into abcd values(3,'xyz')


select * from abcd
id  Name
1   abc
2   pqr
3   xyz
1   abc
2   pqr
3   xyz

Delete Duplicate record but keep Distinct Record in table 

DELETE 
FROM abcd a
WHERE ROWID > (SELECT MIN(ROWID) FROM abcd b
WHERE b.id=a.id
);

run the above query 3 rows delete 

select * from abcd

id  Name 
1   abc
2   pqr
3   xyz
2
Krunal Patel

解決策4)

 delete from emp where rowid in
            (
             select rid from
                (
                  select rowid rid,
                  dense_rank() over(partition by empno order by rowid
                ) rn
             from emp
            )
 where rn > 1
);
2
DoOrDie

1。ソリューション

delete from emp
    where rowid not in
    (select max(rowid) from emp group by empno);

2。sloution

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
               );

.solution

delete from emp e1
         where rowid not in
          (select max(rowid) from emp e2
           where e1.empno = e2.empno ); 

4。ソリューション

 delete from emp where rowid in
            (
             select rid from
                (
                  select rowid rid,
                  dense_rank() over(partition by empno order by rowid
                ) rn
             from emp
            )
 where rn > 1
);
2
user5906974

ROWID-の使用

delete from emp
 where rowid not in
 (select max(rowid) from emp group by empno);

自己結合を使用する

delete from emp e1
 where rowid not in
 (select max(rowid) from emp e2
 where e1.empno = e2.empno );
2

5。ソリューション

delete from emp where rowid in 
    (
      select  rid from
       (
         select rowid rid,rank() over (partition by emp_id order by rowid)rn from emp     
       )
     where rn > 1
    );
2
DoOrDie

本当に大きなテーブルの最速の方法

  1. 以下の構造を持つ例外テーブルを作成します:exceptions_table

    ROW_ID ROWID
    OWNER VARCHAR2(30)
    TABLE_NAME VARCHAR2(30)
    CONSTRAINT VARCHAR2(30)
    
  2. 重複によって違反される一意の制約または主キーを作成してみてください。重複しているため、エラーメッセージが表示されます。例外表には、重複行のROWIDが含まれます。

    alter table add constraint
    unique --or primary key
    (dupfield1,dupfield2) exceptions into exceptions_table;
    
  3. Rowidでexceptions_tableを使用してテーブルに参加し、DUPを削除します

    delete original_dups where rowid in (select ROW_ID from exceptions_table);
    
  4. 削除する行の量が大きい場合は、rowidによってexceptions_tableを使用してアンチジョインする新しいテーブル(すべての権限とインデックスを含む)を作成し、元のテーブルの名前をoriginal_dupsテーブルに変更し、new_table_with_no_dupsの名前を元のテーブルに変更します

    create table new_table_with_no_dups AS (
        select field1, field2 ........ 
        from original_dups t1
        where not exists ( select null from exceptions_table T2 where t1.rowid = t2.row_id )
    )
    
1
user2158672
delete from dept
where rowid in (
     select rowid
     from dept
     minus
     select max(rowid)
     from dept
     group by DEPTNO, DNAME, LOC
);
1
user3655760
DELETE FROM tableName  WHERE ROWID NOT IN (SELECT   MIN (ROWID) FROM table GROUP BY columnname);
1
JgSudhakar

以下のスクリプトを確認してください-

1。

Create table test(id int,sal int); 

2。

    insert into test values(1,100);    
    insert into test values(1,100);    
    insert into test values(2,200);    
    insert into test values(2,200);    
    insert into test values(3,300);    
    insert into test values(3,300);    
    commit;

3。

 select * from test;    

ここに6レコードが表示されます。
4。クエリの下で実行-

delete from 
   test
where rowid in
 (select rowid from 
   (select 
     rowid,
     row_number()
    over 
     (partition by id order by sal) dup
    from test)
  where dup > 1)
  1. select * from test;

重複したレコードが削除されたことがわかります。
これでクエリが解決することを願っています。ありがとう:)

1
Rakesh Roshan

一般的なテーブル式とウィンドウ関数を使用した回答は見当たりませんでした。これが、私が最も使いやすいと思うものです。

DELETE FROM
 YourTable
WHERE
 ROWID IN
    (WITH Duplicates
          AS (SELECT
               ROWID RID, 
               ROW_NUMBER() 
               OVER(
               PARTITION BY First_Name, Last_Name, Birth_Date)
                  AS RN
               SUM(1)
               OVER(
               PARTITION BY First_Name, Last_Name, Birth_Date
               ORDER BY ROWID ROWS BETWEEN UNBOUNDED PRECEDING 
                                       AND UNBOUNDED FOLLOWING)
                   AS CNT
              FROM
               YourTable
              WHERE
               Load_Date IS NULL)
     SELECT
      RID
     FROM
      duplicates
     WHERE
      RN > 1);

注意すべき点:

1)partition句のフィールドの重複のみをチェックしています。

2)他の重複よりも1つの重複を選択する何らかの理由がある場合、order by句を使用して、その行にrow_number()= 1を持たせることができます。

3)N> = 1で最後のwhere句を「Where RN> N」に変更することで、保持される番号の重複を変更できます(N = 0は重複するすべての行を削除すると考えていましたが、すべての行を削除するだけです) 。

4)グループ内の行数を各行にタグ付けするCTEクエリにSumパーティションフィールドを追加しました。したがって、最初の項目を含む重複した行を選択するには、「WHERE cnt> 1」を使用します。

1
Darrel Lee

最高のパフォーマンスを得るために、私が書いたものを以下に示します
(実行計画を参照)

DELETE FROM your_table
WHERE rowid IN 
  (select t1.rowid from your_table  t1
      LEFT OUTER JOIN (
      SELECT MIN(rowid) as rowid, column1,column2, column3
      FROM your_table 
      GROUP BY column1, column2, column3
  )  co1 ON (t1.rowid = co1.rowid)
  WHERE co1.rowid IS NULL
);
0
Enguerrand JORE

解決策:

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
);
0
sandeep gupta
create or replace procedure delete_duplicate_enq as
    cursor c1 is
    select *
    from enquiry;
begin
    for z in c1 loop
        delete enquiry
        where enquiry.enquiryno = z.enquiryno
        and rowid > any
        (select rowid
        from enquiry
        where enquiry.enquiryno = z.enquiryno);
    end loop;
 end delete_duplicate_enq;
0
Ashish sinha