Carlos Mattos

SQL – Como excluir registros duplicados numa tabela sem chave primária.

Um cenário comum no dia-a-dia, quando lidamos com bancos de dados, é a necessidade de identificarmos e removermos registros duplicados numa tabela. A dificuldade aumenta quando não há chave-primária nesta tabela.

 

A seguir vou demonstrar três métodos que podem ser utilizados para esta finalidade.

 

Criando a Tabela de Exemplo

Para ilustrar os métodos que vou apresentar, precisamos criar uma tabela de exemplo. Abaixo está o código para criarmos esta tabela.

 

if exists (select * from sysobjects where name like '%Celebridades%')

      drop table Celebridades

go

 

create table Celebridades(

      PrimeiroNome nvarchar(25),

      Sobrenome nvarchar(25)

)

go

Quadro 1: Criando a tabela de exemplo

 

Uma vez definida a tabela, precisamos alimentá-la com os registros duplicados.

 

insert into Celebridades(PrimeiroNome,Sobrenome) values('Minka','Kelly')

insert into Celebridades(PrimeiroNome,Sobrenome) values('Keeley','Hazell')

insert into Celebridades(PrimeiroNome,Sobrenome) values('Stacy','Ferguson')

insert into Celebridades(PrimeiroNome,Sobrenome) values('Minka','Kelly')

insert into Celebridades(PrimeiroNome,Sobrenome) values('Keeley','Hazell')

insert into Celebridades(PrimeiroNome,Sobrenome) values('Cheryl','Cole')

insert into Celebridades(PrimeiroNome,Sobrenome) values('Jennifer','Garner')

insert into Celebridades(PrimeiroNome,Sobrenome) values('Scarlett','Johanson')

insert into Celebridades(PrimeiroNome,Sobrenome) values('Stacy','Ferguson')

insert into Celebridades(PrimeiroNome,Sobrenome) values('Natalie','Portman')

insert into Celebridades(PrimeiroNome,Sobrenome) values('Katheryn','Winnick')

insert into Celebridades(PrimeiroNome,Sobrenome) values('Minka','Kelly')

insert into Celebridades(PrimeiroNome,Sobrenome) values('Stacy','Ferguson')

insert into Celebridades(PrimeiroNome,Sobrenome) values('Natalie','Portman')

insert into Celebridades(PrimeiroNome,Sobrenome) values('LeeLee','Sobieski')

insert into Celebridades(PrimeiroNome,Sobrenome) values('Megan','Fox')

insert into Celebridades(PrimeiroNome,Sobrenome) values('Minka','Kelly')

insert into Celebridades(PrimeiroNome,Sobrenome) values('Natalie','Portman')

insert into Celebridades(PrimeiroNome,Sobrenome) values('Arianny','Celeste')

insert into Celebridades(PrimeiroNome,Sobrenome) values('Brittney','Palmer')

insert into Celebridades(PrimeiroNome,Sobrenome) values('Natalie','Portman')

insert into Celebridades(PrimeiroNome,Sobrenome) values('Keeley','Hazell')

insert into Celebridades(PrimeiroNome,Sobrenome) values('Megan','Fox')

insert into Celebridades(PrimeiroNome,Sobrenome) values('Minka','Kelly')

Quadro 2: Alimentando a tabela de exemplo com registros duplicados

Você pode observar que em nossa tabela de exemplo alguns registros se repetem por duas, três e até quatro vezes. Agora vamos trabalhar na exclusão dos registros duplicados. Não podemos utilizar a declaração DELETE FROM para excluir os duplicados desta forma:

 

delete from Celebridades where PrimeiroNome = 'Minka' AND Sobrenome = 'Kelly'

 

Este comando excluiria todos os registros com o nome Minka Kelly, e este não é o resultado esperado. Acompanhe a seguir três alternativas diferentes para solucionar esta questão.

 

 

Método 1: Utilizando o SET ROWCOUNT

 

A sintaxe para a declaração SET ROWCOUNT é:

 

SET ROWCOUNT { numero | @var_numero }

 

SET ROWCOUNT limita o SQL Server a processar um número específico de registros. Desta forma, o processo é interrompido após atingir o número de registros informado no argumento. O valor padrão para ROWCOUNT é 0 (zero), o que não estabelece limite para o comando, retornando todos os registros que atendam a cláusula WHERE.

 

Depois de executar o comando ROWCOUNT para limitar os registros que serão retornados pelo SQL, você pode executar o mesmo comando informando 0 (zero) como parametro para desabilitar esta opção.

 

Vamos tomar como exemplo o nome 'Minka Kelly', 5 registros serão retornados.

 

select * from Celebridades where primeironome = 'Minka' and sobrenome = 'Kelly'

 

Neste caso, precisamos excluir 4 dos 5 registros repetidos. Para isto devemos utilizar o ROWCOUNT atribuindo valor 4 para o parametro requerido. Veja o comando a seguir:

 

set rowcount 4

 delete from Celebridades where PrimeiroNome = N'Minka' and Sobrenome = N'Kelly'

set rowcount 0

-- (4 row(s) affected)

 

Depois de executar o comando acima, utilizando a declaração SET ROWCOUNT, execute o comando select e observe o resultado. Os registros repetidos foram excluídos.

 

select PrimeiroNome, Sobrenome from Celebridades

 

Você também pode utilizar o comando SET ROWCOUNT para excluir todos os registros duplicados da tabela de exemplo. Para atingirmos este objetivo, é necessário implementar um CURSOR.

 

Atenção ao declarar o CURSOR para identificar os registros duplicados, você deve definir o parametro do ROWCOUNT igual ao total de registros duplicados - 1, para preservar o registro original que será mantido na base após a execução deste comando.

 

Preste atenção no comando SET ROWCOUNT incluído no corpo do CURSOR.

 

declare @RegistrosDuplicados int

declare @PrimeiroNome nvarchar(25)

declare @Sobrenome nvarchar(25)

 

declare cursorDuplicados cursor fast_forward for

select PrimeiroNome, Sobrenome, count(*) - 1

from Celebridades

group by PrimeiroNome, Sobrenome

having count(*) > 1

 

open cursorDuplicados

 

fetch next from cursorDuplicados into @PrimeiroNome, @Sobrenome, @RegistrosDuplicados

 

while @@fetch_status = 0

 

begin

      set rowcount @RegistrosDuplicados

      delete from Celebridades where PrimeiroNome = @PrimeiroNome and Sobrenome = @Sobrenome

      set rowcount 0

      fetch next from cursorDuplicados into @PrimeiroNome, @Sobrenome, @RegistrosDuplicados

end

 

close cursorDuplicados

deallocate cursorDuplicados

Quadro 3: Utilizando o ROWCOUNT  com CURSOR

 

Método 2: Utilizando TOP

 

Um segundo método que podemos usar para remover registros duplicados é a expressão TOP combinada com a declaração DELETE. Desde o SQL 2005, como uma evolução do T-SQL, a expressão TOP passou a aceitar uma variável onde antes, no SQL 2000, só era possível atribuir uma constante numérica. Com esta mudança, podemos utilizar a expressão TOP dentro de um CURSOR para excluir todos os registros duplicados de uma só vez.

 

Utilizando nossa tabela de exemplo, podemos construir um comando para excluir os registros duplicados com o nome 'Minka Kelly', como apresentado nas linhas a seguir.

 

delete top(4) from Celebridades

 where PrimeiroNome = 'Minka' and Sobrenome = 'Kelly'

 

Trabalhando na mesma linha de raciocínio, podemos construir um CURSOR utilizando a expressão TOP. Veja o código abaixo.

 

declare @RegistrosDuplicados int

declare @PrimeiroNome nvarchar(25)

declare @Sobrenome nvarchar(25)

 

declare cursorDuplicados cursor fast_forward for

select PrimeiroNome, Sobrenome, count(*) - 1

from Celebridades

group by PrimeiroNome, Sobrenome

having count(*) > 1

 

open cursorDuplicados

 

fetch next from cursorDuplicados into @PrimeiroNome, @Sobrenome, @RegistrosDuplicados

 

while @@fetch_status = 0

 

begin

      delete top(@RegistrosDuplicados) from Celebridades where PrimeiroNome = @PrimeiroNome and Sobrenome = @Sobrenome

      fetch next from cursorDuplicados into @PrimeiroNome, @Sobrenome, @RegistrosDuplicados

end

 

close cursorDuplicados

deallocate cursorDuplicados

Quadro 4: Construindo CURSOR com a expressão TOP

 

Considere utilizar o método 2, com a expressão TOP, ao invés de utilizar o ROWCOUNT. A declaração ROWCOUNT não afetará os comandos DELETE, INSERT e UPDATE nas próximas versões do SQL. Consulte o Books On Line para mais informações (http://msdn.microsoft.com/en-us/library/ms188774.aspx).

 

Método 3: Adicionar uma coluna IDENTITY

 

O terceiro método é adicionar uma coluna IDENTITY na nossa tabela de exemplo. Execute o comando a seguir

para adicionar a coluna IDENTITY.

 

alter table Celebridades add Codigo int identity(1,1)

 

Agora, com a coluna IDENTITY podemos utilizar o comando DELETE para excluir os registros duplicados. Veja o exemplo a seguir.

 

delete from Celebridades where Codigo in(24,17,12,4)

 

Com a coluna IDENTITY inserida na nossa tabela de exemplo, podemos utilizar o recurso CTE (Common Table Expression) para excluir os registros duplicados, ao invés de usarmos um CURSOR. As CTEs foram introduzidas como aprimoramento do T-SQL a partir da versão 2005. Desta forma, o código abaixo não funcionará se voce tentar executá-lo no SQL Server 2000.

 

with CTEDuplicados(PrimeiroNome, Sobrenome, Codigo)

as

(

select PrimeiroNome, Sobrenome, Min(Codigo) Codigo

from Celebridades

group by PrimeiroNome, Sobrenome

having count(*) > 1

)

delete from Celebridades

where Codigo in (

select Celebridades.Codigo

from Celebridades

inner join CTEDuplicados

on Celebridades.PrimeiroNome = CTEDuplicados.PrimeiroNome

and Celebridades.Sobrenome = CTEDuplicados.Sobrenome

and Celebridades.Codigo <> CTEDuplicados.Codigo

)

Quadro 5: Utilizando CTE para excluir os registros duplicados

 

Após excluir os registros duplicados utilizando a CTE, você pode remover a coluna IDENTITY da tabela de exemplo executando o comando a seguir:

 

alter table Celebridades drop column Codigo

 

Aprofunde seus conhecimentos sobre este tema visitando a comunidade SQL Server no DevBrasil.

 

Faça download deste arquivo no formato PDF e também do código T-SQL deste exemplo.

Posted: Sat, May 7 2011 20:53 by Carlos Mattos | with 2 comment(s)
Filed under:

Comments

fabio ambrozio said:

excelente artigo.

parabéns e obrigado!

# August 3, 2011 11:58 AM

WERLITON said:

POST magnifico!

Me ajudou bastante e tirou todas minhas dívidas e dificuldades sobre remover registros duplicados!

PARABÉNS!

# September 23, 2011 8:45 AM
Leave a Comment

(required) 

(required) 

(optional)
 

(required) 

If you can't read this number refresh your screen
Enter the numbers above: