Eu tenho uma tabela com uma coluna varchar e gostaria de encontrar todos os registros que tenham valores duplicados nesta coluna. Qual é a melhor consulta que posso usar para encontrar as duplicatas?
Mas como isso é útil se você não pode obter os IDs das linhas com valores duplicados? Sim, você pode fazer uma nova consulta correspondente a cada valor duplicado, mas é possível simplesmente listar as duplicatas?
22414 NobleUplift
23
@NobleUplift Você pode fazer um GROUP_CONCAT(id)e ele listará os IDs. Veja minha resposta para um exemplo.
Matt Rardon
5
O que significaria se dissesse ERROR: column "c" does not exist LINE 1?
Utilizador
15
Estou confuso por que essa é a resposta aceita e por que tem tantos votos positivos. O OP perguntou: "Gostaria de encontrar todos os registros que tenham valores duplicados nesta coluna". Esta resposta retorna uma tabela de contagens. -1
Monica Heddneck 03/04
4
Para aqueles que não entendem como o HAVING funciona - é simplesmente um filtro no conjunto de resultados, o que acontece após a consulta principal.
Essa consulta retorna registros completos, não apenas distintos varchar_column.
Esta consulta não usa COUNT(*). Se houver muitas duplicatas, COUNT(*)for caro e você não precisar do todo COUNT(*), precisará saber se há duas linhas com o mesmo valor.
Ter um índice ativado varchar_columnirá, obviamente, acelerar bastante essa consulta.
Muito bom. Eu adicionei ORDER BY varchar_column DESCao final da consulta.
trante 28/05
8
Esta deve ser a resposta aceita, como GROUP BYe HAVINGretorna apenas uma das possíveis duplicatas. Além disso, desempenho com campo indexado em vez de COUNT(*)e a possibilidade ORDER BYde agrupar registros duplicados.
Rémi Breton
1
Conforme declarado nos comentários acima, esta consulta permite listar todas as linhas duplicadas. Muito útil.
TryHarder 26/08/16
4
Olhando para isso, não entendo como isso funcionaria. A condição interna sempre será verdadeira, pois qualquer linha da tabela externa também estará disponível na tabela interna e, portanto, cada linha sempre corresponderá pelo menos a si mesma? Eu tentei a consulta e obtive o resultado que eu suspeitava - todas as linhas retornavam. Mas com tantos votos positivos, estou duvidando de mim mesmo. Não está faltando na consulta interna algo como "AND mto.id <> mti.id"? Funciona para mim quando adiciono isso.
CLOX
2
@Quassnoi Tudo bem. Eu tentei colocá-lo no sqlfiddle, mas desisti, pois todas as consultas que tento executar, além de criar o esquema, atingiram o tempo limite. Eu descobri que apenas remover "EXISTS" também faz a consulta funcionar corretamente para mim.
Clox
144
Com base na resposta da levik para obter os IDs das linhas duplicadas, você pode fazer isso GROUP_CONCATse o seu servidor suportar (isso retornará uma lista de IDs separados por vírgula).
SELECT GROUP_CONCAT(id), name, COUNT(*) c FROM documents GROUPBY name HAVING c >1;
Todo esse tempo sem saber sobre GROUP_CONCAT ()! muito muito útil
aesede
Realmente apreciado Matt. Isso é realmente útil! Para aqueles que tentam atualizar no phpmyadmin, se você deixar o id junto com a função assim: SELECT id, GROUP_CONCAT(id), name, COUNT(*) c [...]ele permite a edição em linha e deve atualizar todas as linhas envolvidas (ou pelo menos a primeira que corresponda), mas infelizmente a edição gera um erro de Javascript. ..
Armfoot
Como você calcularia quantos IDs estão sujeitos a duplicação?
precisa saber é o seguinte
2
Como não obtenho todos os IDs agrupados, mas listados do primeiro ao último; com todos os seus respectivos valores nas colunas ao lado deles? Portanto, em vez de agrupá-lo, ele mostra apenas o ID 1 e seu valor, o ID 2 e seu valor. MESMO se os valores para o ID forem os mesmos.
MailBlade 15/02
1
Resposta extremamente útil, essa deve ser a melhor opção para que mais pessoas a vejam. Lembro-me da quantidade de dor que passei ao criar essas listas, e estava disponível o tempo todo como comando. #
John John
13
Supondo que sua tabela se chame TableABC e a coluna que você deseja seja Col e a chave primária para T1 seja Key.
SELECT a.Key, b.Key, a.Col FROM TableABC a, TableABC bWHERE a.Col = b.Col AND a.Key<> b.Key
A vantagem dessa abordagem sobre a resposta acima é que ela fornece a chave.
+1 Porque é útil. Embora, ironicamente, o próprio resultado contém duplicatas (ele lista a e b, então b e a.)
Fabien Snauwaert
2
@FabienSnauwaert Você pode se livrar de algumas das duplicatas comparando inferior a (ou superior)
Michael
@TechTravelThink sua resposta é muito clara, obrigado por isso, mas em uma tabela grande leva algum tempo (cerca de 2 min em mais 20.000 tabelas de entradas) e depois de mostrar 25 primeiros resultados, se eu clicar para mostrar o próximo, phpmyadmin show error "# 1052 - A coluna 'id' na cláusula de ordem é ambígua "
bcag2
12
SELECT*FROM`dps`WHERE pid IN(SELECT pid FROM`dps`GROUPBY pid HAVING COUNT(pid)>1)
FYI - Você desejará 'selecionar um somecol distinto ...' se houver a possibilidade de existir mais de 1 registro duplicado, caso contrário, os resultados conterão duplicatas das linhas duplicadas encontradas.
Tirou
7
SELECT t.*,(select count(*)from city as tt
where tt.name=t.name)as count
FROM`city`as t
where(select count(*)from city as tt
where tt.name=t.name
)>1orderby count desc
Substitua cidade pela sua mesa. Substitua nome pelo nome do seu campo
Levando a resposta do @ maxyfc adiante, eu precisava encontrar todas as linhas retornadas com os valores duplicados, para poder editá-las no MySQL Workbench :
SELECT*FROMtableWHERE field IN(SELECT field FROMtableGROUPBY field HAVING count(*)>1)ORDERBY field
Vi o resultado acima e a consulta funcionará bem se você precisar verificar o valor da coluna única duplicada. Por exemplo, email.
Mas se você precisar verificar com mais colunas e desejar verificar a combinação do resultado, para que esta consulta funcione bem:
SELECT COUNT(CONCAT(name,email))AS tot,
name,
email
FROM users
GROUPBY CONCAT(name,email)HAVING tot>1(This query will SHOW the USER list which ARE greater THAN 1AND also COUNT)
Exatamente o que era necessário! Aqui a minha consulta, verificando 3 campos para duplicatas:SELECT COUNT(CONCAT(userid,event,datetime)) AS total, userid, event, datetime FROM mytable GROUP BY CONCAT(userid, event, datetime ) HAVING total>1
Kai Noack
4
Eu prefiro usar funções em janelas (MySQL 8.0+) para encontrar duplicatas porque eu podia ver a linha inteira:
WITH cte AS(SELECT*,COUNT(*)OVER(PARTITIONBY col_name)AS num_of_duplicates_group
,ROW_NUMBER()OVER(PARTITIONBY col_name ORDERBY col_name2)AS pos_in_group
FROMtable)SELECT*FROM cte
WHERE num_of_duplicates_group >1;
SELECT
t.*,(SELECT COUNT(*)FROM city AS tt WHERE tt.name=t.name)AS count
FROM`city`AS t
WHERE(SELECT count(*)FROM city AS tt WHERE tt.name=t.name)>1ORDERBY count DESC
Vale ressaltar que isso é insuportavelmente lento ou pode até não terminar se a coluna que está sendo consultada não estiver indexada. Caso contrário, eu poderia mudar a.emailpara a.*e obter todos os IDs das linhas com duplicatas.
NobleUplift
@NobleUplift Do que você está falando?
Michael
@ Michael Bem, já que ele tem três anos, não posso testar a versão do MySQL que estava usando, mas tentei a mesma consulta em um banco de dados em que a coluna que selecionei não tinha um índice, por isso demorou bastante tempo. alguns segundos para terminar. Alterando para SELECT DISTINCT a.*resolvido quase instantaneamente.
NobleUplift
@NobleUplift Ah ok. Eu posso entender que é lento ... a parte que me preocupa é "talvez nem termine".
Michael
@ Michael Eu não lembro em qual tabela do nosso sistema eu tinha que executar essa consulta, mas para aqueles com alguns milhões de registros provavelmente teriam terminado, mas em um tempo que demorou tanto que eu desisti de ver quando na verdade terminaria.
NobleUplift
1
Para remover linhas duplicadas com vários campos, primeiro cancele-as na nova chave exclusiva especificada para as únicas linhas distintas e, em seguida, use o comando "agrupar por" para remover as linhas duplicadas com a mesma nova chave exclusiva:
Create TEMPORARY table tmp select concat(f1,f2)as cfs,t1.*from mytable as t1;Createindex x_tmp_cfs on tmp(cfs);Createtable unduptable select f1,f2,...from tmp groupby cfs;
Por que não usar CREATE TEMPORARY TABLE ...? Uma pequena explicação da sua solução seria ótima.
maxhb
1
Uma contribuição muito tardia ... no caso de ajudar alguém a passar o tempo ... eu tinha a tarefa de encontrar pares de transações correspondentes (na verdade, ambos os lados das transferências de conta para conta) em um aplicativo bancário, para identificar quais eram 'de' e 'para' para cada transação de transferência entre contas, então acabamos com isso:
SELECT
LEAST(primaryid, secondaryid)AS transactionid1,
GREATEST(primaryid, secondaryid)AS transactionid2
FROM(SELECT table1.transactionid AS primaryid,
table2.transactionid AS secondaryid
FROM financial_transactions table1
INNERJOIN financial_transactions table2
ON table1.accountid = table2.accountid
AND table1.transactionid <> table2.transactionid
AND table1.transactiondate = table2.transactiondate
AND table1.sourceref = table2.destinationref
AND table1.amount =(0- table2.amount))AS DuplicateResultsTable
GROUPBY transactionid1
ORDERBY transactionid1;
O resultado é que ele DuplicateResultsTablefornece linhas contendo transações correspondentes (ou seja, duplicadas), mas também fornece os mesmos IDs de transação ao contrário na segunda vez em que corresponde ao mesmo par; portanto, o externo SELECTestá lá para agrupar pelo primeiro ID de transação, o que é feito usando LEASTe GREATESTpara garantir que as duas transações sejam sempre da mesma ordem nos resultados, o que a torna segura GROUPpela primeira, eliminando todas as correspondências duplicadas. Percorreu quase um milhão de registros e identificou mais de 12.000 partidas em menos de 2 segundos. É claro que o transactionid é o índice principal, o que realmente ajudou.
Respostas:
Faça um
SELECT
com umaGROUP BY
cláusula. Digamos que nome é a coluna na qual você deseja encontrar duplicatas:Isso retornará um resultado com o valor do nome na primeira coluna e uma contagem de quantas vezes esse valor aparece na segunda.
fonte
GROUP_CONCAT(id)
e ele listará os IDs. Veja minha resposta para um exemplo.ERROR: column "c" does not exist LINE 1
?fonte
IN()
/NOT IN()
.Essa consulta retorna registros completos, não apenas distintos
varchar_column
.Esta consulta não usa
COUNT(*)
. Se houver muitas duplicatas,COUNT(*)
for caro e você não precisar do todoCOUNT(*)
, precisará saber se há duas linhas com o mesmo valor.Ter um índice ativado
varchar_column
irá, obviamente, acelerar bastante essa consulta.fonte
ORDER BY varchar_column DESC
ao final da consulta.GROUP BY
eHAVING
retorna apenas uma das possíveis duplicatas. Além disso, desempenho com campo indexado em vez deCOUNT(*)
e a possibilidadeORDER BY
de agrupar registros duplicados.Com base na resposta da levik para obter os IDs das linhas duplicadas, você pode fazer isso
GROUP_CONCAT
se o seu servidor suportar (isso retornará uma lista de IDs separados por vírgula).fonte
SELECT id, GROUP_CONCAT(id), name, COUNT(*) c [...]
ele permite a edição em linha e deve atualizar todas as linhas envolvidas (ou pelo menos a primeira que corresponda), mas infelizmente a edição gera um erro de Javascript. ..Supondo que sua tabela se chame TableABC e a coluna que você deseja seja Col e a chave primária para T1 seja Key.
A vantagem dessa abordagem sobre a resposta acima é que ela fornece a chave.
fonte
fonte
Para descobrir quantos registros estão duplicados na coluna de nome em Funcionário, a consulta abaixo é útil;
fonte
para obter todos os dados que contêm duplicação, usei isso:
TableName = a tabela com a qual você está trabalhando.
DupliactedData = os dados duplicados que você está procurando.
fonte
Minha consulta final incorporou algumas das respostas aqui que ajudaram - combinando agrupar por, contar & GROUP_CONCAT.
Isso fornece a identificação dos dois exemplos (separados por vírgula), o código de barras que eu precisava e quantas duplicatas.
Mude a tabela e as colunas adequadamente.
fonte
Não estou vendo nenhuma abordagem JOIN, que tem muitos usos em termos de duplicatas.
Essa abordagem fornece resultados dobrados reais.
fonte
Substitua cidade pela sua mesa. Substitua nome pelo nome do seu campo
fonte
Levando a resposta do @ maxyfc adiante, eu precisava encontrar todas as linhas retornadas com os valores duplicados, para poder editá-las no MySQL Workbench :
fonte
Vi o resultado acima e a consulta funcionará bem se você precisar verificar o valor da coluna única duplicada. Por exemplo, email.
Mas se você precisar verificar com mais colunas e desejar verificar a combinação do resultado, para que esta consulta funcione bem:
fonte
SELECT COUNT(CONCAT(userid,event,datetime)) AS total, userid, event, datetime FROM mytable GROUP BY CONCAT(userid, event, datetime ) HAVING total>1
Eu prefiro usar funções em janelas (MySQL 8.0+) para encontrar duplicatas porque eu podia ver a linha inteira:
DB Fiddle Demo
fonte
fonte
A seguir, você encontrará todos os product_id usados mais de uma vez. Você obtém apenas um registro para cada product_id.
Código extraído de: http://chandreshrana.blogspot.in/2014/12/find-duplicate-records-based-on-any.html
fonte
fonte
fonte
a.email
paraa.*
e obter todos os IDs das linhas com duplicatas.SELECT DISTINCT a.*
resolvido quase instantaneamente.Para remover linhas duplicadas com vários campos, primeiro cancele-as na nova chave exclusiva especificada para as únicas linhas distintas e, em seguida, use o comando "agrupar por" para remover as linhas duplicadas com a mesma nova chave exclusiva:
fonte
CREATE TEMPORARY TABLE ...
? Uma pequena explicação da sua solução seria ótima.Uma contribuição muito tardia ... no caso de ajudar alguém a passar o tempo ... eu tinha a tarefa de encontrar pares de transações correspondentes (na verdade, ambos os lados das transferências de conta para conta) em um aplicativo bancário, para identificar quais eram 'de' e 'para' para cada transação de transferência entre contas, então acabamos com isso:
O resultado é que ele
DuplicateResultsTable
fornece linhas contendo transações correspondentes (ou seja, duplicadas), mas também fornece os mesmos IDs de transação ao contrário na segunda vez em que corresponde ao mesmo par; portanto, o externoSELECT
está lá para agrupar pelo primeiro ID de transação, o que é feito usandoLEAST
eGREATEST
para garantir que as duas transações sejam sempre da mesma ordem nos resultados, o que a torna seguraGROUP
pela primeira, eliminando todas as correspondências duplicadas. Percorreu quase um milhão de registros e identificou mais de 12.000 partidas em menos de 2 segundos. É claro que o transactionid é o índice principal, o que realmente ajudou.fonte
fonte
fonte
Se você deseja remover o uso duplicado
DISTINCT
Caso contrário, use esta consulta:
SELECT users.*,COUNT(user_ID) as user FROM users GROUP BY user_name HAVING user > 1;
fonte
Tente usar esta consulta:
fonte