Aqui estão onze opções para retornar linhas duplicadas no SQLite quando essas linhas têm uma chave primária ou alguma outra coluna de identificador exclusivo (mas você deseja ignorar a chave primária).
Isso significa que as linhas duplicadas compartilham exatamente os mesmos valores em todas as colunas, com exceção da coluna de chave primária/ID exclusivo.
Dados de amostra
Usaremos os seguintes dados para nossos exemplos:
SELECT * FROM Dogs;
Resultado:
DogId FirstName LastName----- --------- --------1 Bark Smith 2 Bark Smith 3 Woof Jones 4 Ruff Robinson5 Wag Johnson 6 Wag Johnson 7 Wag Johnson
As duas primeiras linhas são duplicadas (exceto para oDogId
coluna, que é a chave primária da tabela e contém um valor exclusivo em todas as linhas). As últimas três linhas também são duplicadas (exceto para oDogId
coluna).
A coluna de chave primária garante que não haja linhas duplicadas, o que é uma boa prática em RDBMSs, pois as chaves primárias ajudam a reforçar a integridade dos dados. Mas como as chaves primárias evitam linhas duplicadas, elas têm o potencial de interferir em nossa capacidade de encontrar duplicatas.
Em nossa tabela acima, a coluna de chave primária é um número crescente e seu valor não tem significado e não é significativo. Portanto, precisamos ignorar essa linha se quisermos encontrar duplicatas nas outras colunas.
Opção 1
Podemos executar uma consulta com oGROUP BY
cláusula para agrupar as colunas por suas colunas significativas, então use oCOUNT()
função para retornar o número de linhas idênticas:
SELECT FirstName, LastName, COUNT(*) AS Count FROM Dogs GROUP BY FirstName, LastName ORDER BY Count DESC;
Resultado:
Nome Sobrenome Contagem --------- -------- -----Wag Johnson 3 Bark Smith 2 Ruff Robinson 1 Woof Jones 1
Aqui excluímos a coluna de chave primária omitindo-a de nossa consulta. Também ordenamos por contagem em ordem decrescente, para que as duplicatas apareçam primeiro.
O resultado nos diz que existem três linhas contendo Wag Johnson e duas linhas contendo Bark Smith. Estes são duplicados (ou triplicados no caso de Wag Johnson). As outras duas linhas não têm duplicatas.
Opção 2
Podemos usar oHAVING
cláusula para excluir não duplicados da saída:
SELECT FirstName, LastName, COUNT(*) AS Count FROM Dogs GROUP BY FirstName, LastName HAVING COUNT(*) > 1 ORDER BY Count DESC;
Resultado:
Nome Sobrenome Contagem --------- -------- -----Wag Johnson 3 Bark Smith 2Opção 3
Aqui está um exemplo de verificação de duplicatas em colunas concatenadas. Neste caso, usamos oDISTINCT
palavra-chave para obter valores distintos, então use oCOUNT()
função para retornar a contagem:
SELECT DISTINCT FirstName || ' ' || LastName AS DogName, COUNT(*) AS Count FROM Dogs GROUP BY FirstName || ' ' || LastName ORDER BY Count DESC;
Resultado:
Contagem de nomes de cachorro------------- -----Wag Johnson 3 Bark Smith 2 Woof Jones 1 Ruff Robinson 1Opção 4
Por padrão, cada linha no SQLite tem uma coluna especial, geralmente chamada derowid
, que identifica exclusivamente essa linha na tabela. A menos que tenha sido explicitamente removido da tabela, você pode usá-lo como um identificador exclusivo para cada linha.
Podemos, portanto, usar orowid
em nossa consulta:
SELECT * FROM Dogs WHERE EXISTS ( SELECT 1 FROM Dogs d2 WHERE Dogs.FirstName = d2.FirstName AND Dogs.LastName = d2.LastName AND Dogs.rowid > d2.rowid );
Resultado:
DogId FirstName LastName----- --------- --------2 Bark Smith 6 Wag Johnson 7 Wag Johnson
Poderíamos substituir oSELECT *
comDELETE
para realizar uma operação de desduplicação na mesa.
Observe que poderíamos ter usado oDogId
coluna (nossa chave primária) em vez dorowid
se quiséssemos. Dito isso, orowid
pode ser útil se você não puder usar a coluna de chave primária por algum motivo ou se a tabela não tiver uma chave primária.
Opção 5
Aqui está outra consulta que usa orowid
:
SELECT * FROM Dogs WHERE rowid > ( SELECT MIN(rowid) FROM Dogs d2 WHERE Dogs.FirstName = d2.FirstName AND Dogs.LastName = d2.LastName );
Resultado:
DogId FirstName LastName----- --------- --------2 Bark Smith 6 Wag Johnson 7 Wag Johnson
Assim como no exemplo anterior, poderíamos substituir oSELECT *
comDELETE
para excluir as linhas duplicadas.
Opção 6
Os doisrowid
as opções acima são ótimas se você deve ignorar completamente a chave primária em sua consulta (ou se você não tiver uma coluna de chave primária). No entanto, como mencionado, ainda há a opção de substituirrowid
com a coluna de chave primária – no nosso caso oDogId
coluna:
SELECT * FROM Dogs WHERE EXISTS ( SELECT 1 FROM Dogs d2 WHERE Dogs.FirstName = d2.FirstName AND Dogs.LastName = d2.LastName AND Dogs.DogId > d2.DogId );
Resultado:
DogId FirstName LastName----- --------- --------2 Bark Smith 6 Wag Johnson 7 Wag JohnsonOpção 7
E aqui está a outra consulta com orowid
substituído peloDogId
coluna:
SELECT * FROM Dogs WHERE DogId > ( SELECT MIN(DogId) FROM Dogs d2 WHERE Dogs.FirstName = d2.FirstName AND Dogs.LastName = d2.LastName );
Resultado:
DogId FirstName LastName----- --------- --------2 Bark Smith 6 Wag Johnson 7 Wag JohnsonOpção 8
Outra maneira de fazer isso é usar oROW_NUMBER()
função da janela:
SELECT *, ROW_NUMBER() OVER ( PARTITION BY FirstName, LastName ORDER BY FirstName, LastName ) AS Row_Number FROM Dogs;
Resultado:
DogId FirstName LastName Row_Number----- --------- -------- ----------1 Bark Smith 1 2 Bark Smith 2 4 Ruff Robinson 1 5 Wag Johnson 1 6 Wag Johnson 2 7 Wag Johnson 3 3 Woof Jones 1
Usando aPARTITION
cláusula resulta na adição de uma nova coluna, com um número de linha que aumenta cada vez que há uma duplicata, mas é redefinido novamente quando há uma linha única.
Nesse caso, não agrupamos os resultados, o que significa que podemos ver cada linha duplicada, incluindo sua coluna de identificador exclusivo.
Opção 9
Também podemos usar o exemplo anterior como uma expressão de tabela comum em uma consulta maior:
WITH cte AS ( SELECT *, ROW_NUMBER() OVER ( PARTITION BY FirstName, LastName ORDER BY FirstName, LastName ) AS Row_Number FROM Dogs ) SELECT * FROM cte WHERE Row_Number <> 1;
Resultado:
DogId FirstName LastName Row_Number----- --------- -------- ----------2 Bark Smith 2 6 Wag Johnson 2 7 Wag Johnson 3
Isso exclui não duplicados da saída e exclui uma linha de cada duplicata da saída.
Opção 10
Aqui está outra maneira de obter a mesma saída do exemplo anterior:
SELECT * FROM Dogs WHERE DogId IN ( SELECT DogId FROM Dogs EXCEPT SELECT MIN(DogId) FROM Dogs GROUP BY FirstName, LastName );
Resultado:
DogId FirstName LastName----- --------- --------2 Bark Smith 6 Wag Johnson 7 Wag JohnsonOpção 11
Aqui está outra opção para selecionar duplicatas da nossa tabela:
SELECT * FROM Dogs d1, Dogs d2 WHERE d1.FirstName = d2.FirstName AND d1.LastName = d2.LastName AND d1.DogId <> d2.DogId AND d1.DogId = ( SELECT MAX(DogId) FROM Dogs d3 WHERE d3.FirstName = d1.FirstName AND d3.LastName = d1.LastName );
Resultado:
DogId FirstName LastName DogId FirstName LastName----- --------- -------- ----- --------- ----- ---2 Bark Smith 1 Bark Smith 7 Wag Johnson 5 Wag Johnson 7 Wag Johnson 6 Wag Johnson