Removendo linhas duplicadas da tabela no Oracle
-
22-08-2019 - |
Pergunta
Eu estou testando algo em Oracle e povoada uma tabela com alguns dados de exemplo, mas no processo I carregada acidentalmente registros duplicados, então agora eu não posso criar uma chave primária usando algumas das colunas.
Como posso excluir todas as linhas duplicadas e deixar apenas um deles?
Solução
Use o pseudocoluna rowid
.
DELETE FROM your_table
WHERE rowid not in
(SELECT MIN(rowid)
FROM your_table
GROUP BY column1, column2, column3);
Onde column1
, column2
e column3
compõem a chave de identificação para cada registro. Você pode listar todas as suas colunas.
Outras dicas
A partir 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);
(fixa o parêntese ausente)
A partir DevX.com :
DELETE FROM our_table
WHERE rowid not in
(SELECT MIN(rowid)
FROM our_table
GROUP BY column1, column2, column3...) ;
Onde column1, column2, etc. é a chave que você deseja usar.
DELETE FROM tablename a
WHERE a.ROWID > ANY (SELECT b.ROWID
FROM tablename b
WHERE a.fieldname = b.fieldname
AND a.fieldname2 = b.fieldname2)
Solução 1)
delete from emp
where rowid not in
(select max(rowid) from emp group by empno);
Solução 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
);
Solução 3)
delete from emp e1
where rowid not in
(select max(rowid) from emp e2
where e1.empno = e2.empno );
criar tabela t2 como select * distinto de t1;
Você deve fazer uma pl / sql pequeno bloco usando um cursor para loop e excluir as linhas que você não deseja manter. Por exemplo:
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;
Para selecionar as duplicatas apenas o formato de consulta pode ser:
SELECT GroupFunction(column1), GroupFunction(column2),...,
COUNT(column1), column1, column2...
FROM our_table
GROUP BY column1, column2, column3...
HAVING COUNT(column1) > 1
Assim, a consulta correta de acordo com outra sugestão é:
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....)
Esta consulta irá manter o registro mais antigo no banco de dados para os critérios escolhidos na WHERE CLAUSE
.
Oracle Certified Associate (2008)
Usando rowid -
delete from emp
where rowid not in
(select max(rowid) from emp group by empno);
Usando auto juntar -
delete from emp e1
where rowid not in
(select max(rowid) from emp e2
where e1.empno = e2.empno );
Solução 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. solução
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. solução
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. solução
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 você também pode excluir registros duplicados de outra maneira
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
);
A maneira mais rápida para tabelas realmente grandes
-
Criar tabela de exceção com a estrutura a seguir: exceptions_table
ROW_ID ROWID OWNER VARCHAR2(30) TABLE_NAME VARCHAR2(30) CONSTRAINT VARCHAR2(30)
-
Tente criar uma restrição exclusiva ou chave primária que será violada pelos duplicatas. Você receberá uma mensagem de erro porque você tem duplicatas. A tabela exceções conterá os rowids para as linhas duplicadas.
alter table add constraint unique --or primary key (dupfield1,dupfield2) exceptions into exceptions_table;
-
Junte-se a sua mesa com exceptions_table por rowid e dups excluir
delete original_dups where rowid in (select ROW_ID from exceptions_table);
-
Se a quantidade de linhas para apagar é grande, em seguida, criar uma nova tabela (com todas as subvenções e índices) anti-unindo com exceptions_table por rowid e renomear a tabela original na tabela original_dups e renomeie new_table_with_no_dups na tabela original
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 ) )
Confira abaixo roteiros -
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;
Você vai ver aqui 6-registros.
4.run abaixo consulta -
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;
Você verá que os registros duplicados foram excluídos.
Espero que isso resolve sua consulta.
Obrigado :)
Eu não vi quaisquer respostas que usam expressões de tabela comuns e funções da janela. Isto é o que eu acho mais fácil de trabalhar.
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);
Algumas coisas a nota:
1) Estamos apenas a verificação de duplicação nos campos na cláusula partição.
2) Se você tem alguma razão para escolher um duplicar sobre os outros você pode usar uma cláusula ORDER BY para fazer essa linha terá row_number () = 1
3) Você pode alterar o número duplicado preservada mudando a final, onde cláusula para "Onde RN> N" com N> = 1 (eu estava pensando N = 0 iria excluir todas as linhas que têm duplicatas, mas seria apenas de exclusão todas as linhas).
4) Adicionado o campo partição Sum a consulta CTE que irá marcar cada linha com as linhas número do grupo. Então, para selecionar linhas com duplicatas, incluindo o primeiro item utilize "ONDE 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;
Para um melhor desempenho, aqui está o que eu escrevi:
(Ver plano de execução)
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
);
Solução:
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
);