Remover duplicados de uma tabela

votos
5

O tipo de base de dados é PostGres 8,3.

Se eu escrevi:

SELECT field1, field2, field3, count(*) 
FROM table1
GROUP BY field1, field2, field3 having count(*) > 1;

Tenho algumas linhas que têm uma contagem de mais de 1. Como posso tirar o duplicado (eu ainda quero 1 linha para cada um deles, em vez de uma linha ... Eu não quero excluí-los todos.)

Exemplo:

1-2-3
1-2-3
1-2-3
2-3-4
4-5-6

Deve se tornar :

1-2-3
2-3-4
4-5-6

A única resposta que encontrei é , mas eu estou querendo saber se eu poderia fazê-lo sem coluna hash.

Aviso eu não tenho uma PK com um número único, então não posso usar a técnica de min (...). A PK é os 3 campos.

Publicado 28/10/2008 em 15:38
fonte usuário
Em outras línguas...                            


7 respostas

votos
0

Uma resposta possível é:

CREATE <temporary table> (<correct structure for table being cleaned>);
BEGIN WORK;   -- if needed
INSERT IGNORE  INTO <temporary table> SELECT DISTINCT * FROM <source table>;
DELETE FROM <source table>
INSERT IGNORE  INTO <source table> SELECT * FROM <temporary table>;
COMMIT WORK;  -- needed
DROP <temporary table>;

Eu não tenho certeza se o 'trabalho' é necessário em instruções de transação, nem se a explícita BEGIN é necessário no PostgreSQL. Mas o conceito se aplica a qualquer DBMS.

A única coisa para ter cuidado com é restrições de referência e, em particular, desencadeada excluir operações. Se aqueles existir, isso pode ser menos satisfatória.

Respondeu 28/10/2008 em 15:58
fonte usuário

votos
6

Esta é uma das muitas razões que todas as tabelas devem ter uma chave primária (não necessariamente um número de identificação ou identidade, mas uma combinação de uma ou mais colunas que identifica exclusivamente uma linha e que tem a sua singularidade executada no banco de dados).

Sua melhor aposta é algo como isto:

SELECT field1, field2, field3, count(*) 
INTO temp_table1
FROM table1
GROUP BY field1, field2, field3 having count(*) > 1

DELETE T1
FROM table1 T1
INNER JOIN (SELECT field1, field2, field3
      FROM table1
      GROUP BY field1, field2, field3 having count(*) > 1) SQ ON
            SQ.field1 = T1.field1 AND
            SQ.field2 = T1.field2 AND
            SQ.field3 = T1.field3

INSERT IGNORE  INTO table1 (field1, field2, field3)
SELECT field1, field2, field3
FROM temp_table1

DROP TABLE temp_table1
Respondeu 28/10/2008 em 15:59
fonte usuário

votos
0

Isto irá usar o OID Object ID (se a tabela foi criada com ele):

DELETE FROM table1
WHERE OID NOT IN (SELECT   MIN (OID)
                              FROM table1
                          GROUP BY field1, field2, field3)
Respondeu 28/10/2008 em 16:00
fonte usuário

votos
0

Bem, eu deveria interpretar mal alguma coisa, mas eu vou dizer:

SELECIONE DISTINCT field1, field2, field3 FROM table1

Fácil demais para ser bom? ^^

Respondeu 28/10/2008 em 16:04
fonte usuário

votos
0

Usando TSQL, nenhuma idéia se Postgres suporta tabelas temporárias, mas você pode selecionar em uma tabela temporária, em seguida, percorrer e excluir e inserir os resultados de volta para o original

-- **Disclaimer** using TSQL
-- You could select your records into a temp table with a pk
Create Table #dupes
([id] int not null identity(1,1), f1 int, f2 int, f3 int)

Insert Into #dupes (f1,f2,f3) values (1,2,3)
Insert Into #dupes (f1,f2,f3) values (1,2,3)
Insert Into #dupes (f1,f2,f3) values (1,2,3)
Insert Into #dupes (f1,f2,f3) values (2,3,4)
Insert Into #dupes (f1,f2,f3) values (4,5,6)
Insert Into #dupes (f1,f2,f3) values (4,5,6)
Insert Into #dupes (f1,f2,f3) values (4,5,6)
Insert Into #dupes (f1,f2,f3) values (7,8,9)

Select f1,f2,f3 From #dupes

Declare @rowCount int
Declare @counter int
Set @counter = 1
Set @rowCount = (Select Count([id]) from #dupes)

while (@counter < @rowCount + 1)
    Begin
       Delete From #dupes
       Where [Id] <> 
            (Select [id] From #dupes where [id]=@counter)
                and
            (
                [f1] = (Select [f1] from #dupes where [id]=@counter)
                and
                [f2] = (Select [f2] from #dupes where [id]=@counter)
                and
                [f3] = (Select [f3] from #dupes where [id]=@counter)
            )
       Set @counter = @counter + 1
    End

Select f1,f2,f3 From #dupes -- You could take these results and pump them back into --your original table

Drop Table #dupes

Testado isso em MS SQL Server 2000. Não está familiarizado com opções Postgres' mas talvez isso vai levar você na direção certa.

Respondeu 28/10/2008 em 16:05
fonte usuário

votos
0

Este é o método mais simples que eu encontrei:

sintaxe Postgre SQL:

CREATE TABLE tmp AS SELECT distinct * FROM table1
truncate table table1
insert into table1 select * from tmp
drop table tmp

sintaxe T-SQL:

select distinct * into #tmp from table1
truncate table table1
insert into table1 select * from #tmp
drop table #tmp
Respondeu 28/10/2008 em 16:09
fonte usuário

votos
0

Uma boa resposta para este problema, mas para SQL Server. Ele usa o ROWCOUNT que o SQL ofertas Server, para um bom efeito. Eu nunca usei PostgreSQL e, portanto, não sabe o equivalente a ROWCOUNT no PostgreSQL.

Respondeu 28/10/2008 em 16:23
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more