Se você acha que uma tabela MySQL pode ter linhas duplicadas, você pode usar as seguintes opções para retornar todas as duplicatas.
Dados de amostra
Suponha que temos uma tabela com os seguintes dados:
SELECT * FROM Pets;
Resultado:
+-------+---------+---------+ | PetId | PetName | PetType | +-------+---------+---------+ | 1 | Wag | Dog | | 1 | Wag | Dog | | 2 | Scratch | Cat | | 3 | Tweet | Bird | | 4 | Bark | Dog | | 4 | Bark | Dog | | 4 | Bark | Dog | +-------+---------+---------+
As duas primeiras linhas são duplicadas, assim como as três últimas linhas. As linhas duplicadas compartilham os mesmos valores em todas as colunas.
Opção 1
Uma opção é usar a seguinte consulta para retornar linhas duplicadas:
SELECT
DISTINCT PetId,
COUNT(*) AS "Count"
FROM Pets
GROUP BY PetId
ORDER BY PetId;
Resultado:
+-------+-------+ | PetId | Count | +-------+-------+ | 1 | 2 | | 2 | 1 | | 3 | 1 | | 4 | 3 | +-------+-------+
Podemos expandir o
SELECT
list para incluir mais colunas, se necessário:SELECT
PetId,
PetName,
PetType,
COUNT(*) AS "Count"
FROM Pets
GROUP BY
PetId,
PetName,
PetType
ORDER BY PetId;
Resultado:
+-------+---------+---------+-------+ | PetId | PetName | PetType | Count | +-------+---------+---------+-------+ | 1 | Wag | Dog | 2 | | 2 | Scratch | Cat | 1 | | 3 | Tweet | Bird | 1 | | 4 | Bark | Dog | 3 | +-------+---------+---------+-------+
Podemos fazer com que as duplicatas apareçam primeiro ordenando-as por contagem em ordem decrescente:
SELECT
PetId,
PetName,
PetType,
COUNT(*) AS "Count"
FROM Pets
GROUP BY
PetId,
PetName,
PetType
ORDER BY Count DESC;
Resultado:
+-------+---------+---------+-------+ | PetId | PetName | PetType | Count | +-------+---------+---------+-------+ | 4 | Bark | Dog | 3 | | 1 | Wag | Dog | 2 | | 2 | Scratch | Cat | 1 | | 3 | Tweet | Bird | 1 | +-------+---------+---------+-------+
Opção 2
Se quisermos apenas listar as linhas duplicadas, podemos usar o
HAVING
cláusula para excluir não duplicados da saída:SELECT
PetId,
PetName,
PetType,
COUNT(*) AS "Count"
FROM Pets
GROUP BY
PetId,
PetName,
PetType
HAVING COUNT(*) > 1
ORDER BY PetId;
Resultado:
+-------+---------+---------+-------+ | PetId | PetName | PetType | Count | +-------+---------+---------+-------+ | 1 | Wag | Dog | 2 | | 4 | Bark | Dog | 3 | +-------+---------+---------+-------+
Opção 3
Outra maneira de fazer isso é usar o
ROW_NUMBER()
função com a função PARTITION BY
cláusula para numerar a saída do conjunto de resultados. SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY PetId, PetName, PetType
ORDER BY PetId, PetName, PetType
) AS rn
FROM Pets;
Resultado:
+-------+---------+---------+----+ | PetId | PetName | PetType | rn | +-------+---------+---------+----+ | 1 | Wag | Dog | 1 | | 1 | Wag | Dog | 2 | | 2 | Scratch | Cat | 1 | | 3 | Tweet | Bird | 1 | | 4 | Bark | Dog | 1 | | 4 | Bark | Dog | 2 | | 4 | Bark | Dog | 3 | +-------+---------+---------+----+
A
PARTITION BY
cláusula divide o conjunto de resultados produzido pelo FROM
cláusula em partições às quais a função é aplicada. Quando especificamos partições para o conjunto de resultados, cada partição faz com que a numeração comece novamente (ou seja, a numeração começará em 1 para a primeira linha de cada partição). Opção 4
Para retornar apenas as linhas excedentes das duplicatas correspondentes, podemos usar a consulta acima como uma expressão de tabela comum, assim:
WITH cte AS
(
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY PetId, PetName, PetType
ORDER BY PetId, PetName, PetType
) AS rn
FROM Pets
)
SELECT * FROM cte WHERE rn <> 1;
Resultado:
+-------+---------+---------+----+ | PetId | PetName | PetType | rn | +-------+---------+---------+----+ | 1 | Wag | Dog | 2 | | 4 | Bark | Dog | 2 | | 4 | Bark | Dog | 3 | +-------+---------+---------+----+