Rimuovere le righe duplicate dalla tabella in Oracle
-
22-08-2019 - |
Domanda
sto testando qualcosa in Oracle e popolato una tabella con alcuni dati di esempio, ma nel processo sbaglio ho caricato i record duplicati, così ora non riesco a creare una chiave primaria utilizzando alcune delle colonne.
Come faccio a eliminare tutte le righe duplicate e lasciare solo uno di loro?
Soluzione
Utilizzare la pseudocolonna rowid
.
DELETE FROM your_table
WHERE rowid not in
(SELECT MIN(rowid)
FROM your_table
GROUP BY column1, column2, column3);
Dove column1
, column2
, e column3
costituiscono la chiave di identificazione per ogni record. Si potrebbe elencare tutte le colonne.
Altri suggerimenti
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);
(fissa la parentesi mancante)
DevX.com :
DELETE FROM our_table
WHERE rowid not in
(SELECT MIN(rowid)
FROM our_table
GROUP BY column1, column2, column3...) ;
Dove column1, column2, ecc è la chiave che si desidera utilizzare.
DELETE FROM tablename a
WHERE a.ROWID > ANY (SELECT b.ROWID
FROM tablename b
WHERE a.fieldname = b.fieldname
AND a.fieldname2 = b.fieldname2)
Soluzione 1)
delete from emp
where rowid not in
(select max(rowid) from emp group by empno);
Soluzione 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
);
Soluzione 3)
delete from emp e1
where rowid not in
(select max(rowid) from emp e2
where e1.empno = e2.empno );
create table t2 as select * distinto da t1;
Si dovrebbe fare un piccolo blocco PL / SQL utilizzando un cursore per il ciclo e cancellare le righe che non si desidera conservare. Per esempio:
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;
Per selezionare i duplicati solo il formato query può essere:
SELECT GroupFunction(column1), GroupFunction(column2),...,
COUNT(column1), column1, column2...
FROM our_table
GROUP BY column1, column2, column3...
HAVING COUNT(column1) > 1
Quindi, la domanda corretta come per altro suggerimento è:
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....)
Questa query manterrà il record più vecchio in database per i criteri scelti nel WHERE CLAUSE
.
Oracle Certified Associate (2008)
Utilizzando rowid -
delete from emp
where rowid not in
(select max(rowid) from emp group by empno);
Utilizzando auto unirsi -
delete from emp e1
where rowid not in
(select max(rowid) from emp e2
where e1.empno = e2.empno );
Soluzione 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
);
1. Soluzione
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
);
3.solution
delete from emp e1
where rowid not in
(select max(rowid) from emp e2
where e1.empno = e2.empno );
4. Soluzione
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
);
5. Soluzione
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
);
DELETE from table_name where rowid not in (select min(rowid) FROM table_name group by column_name);
e si può anche eliminare i record duplicati in un altro modo
DELETE from table_name a where rowid > (select min(rowid) FROM table_name b where a.column=b.column);
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
DELETE FROM tableName WHERE ROWID NOT IN (SELECT MIN (ROWID) FROM table GROUP BY columnname);
delete from dept
where rowid in (
select rowid
from dept
minus
select max(rowid)
from dept
group by DEPTNO, DNAME, LOC
);
Il modo più veloce per davvero grandi tavoli
-
Crea una tabella eccezione con la struttura di seguito: exceptions_table
ROW_ID ROWID OWNER VARCHAR2(30) TABLE_NAME VARCHAR2(30) CONSTRAINT VARCHAR2(30)
-
Prova creare un vincolo univoco o una chiave primaria che verrà violata dai duplicati. Si otterrà un messaggio di errore perché avete i duplicati. La tabella di eccezioni conterrà i ROWIDs per le righe duplicate.
alter table add constraint unique --or primary key (dupfield1,dupfield2) exceptions into exceptions_table;
-
unire la vostra tavola con exceptions_table da identificativo ed eliminare dups
delete original_dups where rowid in (select ROW_ID from exceptions_table);
-
Se la quantità di righe da eliminare è grande, quindi creare una nuova tabella (con tutte le sovvenzioni e gli indici) anti-giunzione con exceptions_table da rowid e rinominare la tabella originale nella tabella original_dups e rinominare new_table_with_no_dups nella tabella originale
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 ) )
Controlla qui sotto scripts -
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;
Si vedrà qui 6-records.
4.run sotto interrogazione -
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)
-
select * from test;
Si vedrà che i record duplicati sono stati cancellati.
Spero che questo risolve la query.
Grazie :)
Non ho visto alcuna risposta che utilizzano espressioni di tabella comuni e funzioni finestra. Questo è ciò che trovo più facile da lavorare.
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);
Qualcosa da notare:
1) Stiamo verificando solo per la duplicazione sui campi nella clausola partizione.
2) Se avete qualche motivo per scegliere un duplicato rispetto alle altre è possibile utilizzare una clausola ORDER BY di rendere quella riga avrà row_number () = 1
3) È possibile modificare il duplicato numero conservato cambiando il finale in cui la clausola di "Dove RN> N" con N> = 1 (stavo pensando N = 0 sarebbe eliminare tutte le righe che hanno i duplicati, ma sarebbe semplicemente cancellare tutte le righe).
4) Aggiunto il campo di partizione Somma query CTE che contrassegnare ogni riga con le righe dei numeri del gruppo. Quindi, per selezionare le righe con i duplicati, tra cui il primo uso voce "DOVE cnt> 1".
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;
Per ottenere prestazioni ottimali, ecco quello che ho scritto:
(Vedi piano di esecuzione)
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
);
soluzione:
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
);