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.

2 thoughts on “SQL – Como excluir registros duplicados numa tabela sem chave primária.”

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>