J'ai une table avec une colonne varchar, et je voudrais trouver tous les enregistrements qui ont des valeurs en double dans cette colonne. Quelle est la meilleure requête que je puisse utiliser pour trouver les doublons?
Puisque vous avez mentionné trouver tous les enregistrements, je suppose que vous devez connaître les CLÉS ainsi que les VALEURS dupliquées dans cette colonne varchar.
TechTravelThink
Je peux trouver les clés assez facilement après avoir obtenu les valeurs, je veux vraiment juste une liste de toutes les valeurs en double.
Jon Tackabury
Réponses:
1523
Faites un SELECTavec une GROUP BYclause. Disons que le nom est la colonne dans laquelle vous souhaitez trouver des doublons:
SELECT name, COUNT(*) c FROMtableGROUPBY name HAVING c >1;
Cela renverra un résultat avec la valeur du nom dans la première colonne et un nombre de fois que cette valeur apparaîtra dans la seconde.
Mais comment est-ce utile si vous ne pouvez pas obtenir les ID des lignes avec des valeurs en double? Oui, vous pouvez faire une nouvelle requête correspondant à chaque valeur en double, mais est-il possible de simplement lister les doublons?
NobleUplift
23
@NobleUplift Vous pouvez faire un GROUP_CONCAT(id)et il listera les identifiants. Voir ma réponse pour un exemple.
Matt Rardon
5
Qu'est-ce que cela signifierait s'il disait ERROR: column "c" does not exist LINE 1?
Utilisateur
15
Je ne comprends pas pourquoi c'est la réponse acceptée et pourquoi il y a tant de votes positifs. L'OP a demandé: "Je voudrais trouver tous les enregistrements qui ont des valeurs en double dans cette colonne." Cette réponse renvoie une table de décomptes. -1
Monica Heddneck
4
Pour ceux qui ne comprennent pas comment fonctionne HAVING - il s'agit simplement d'un filtre sur l'ensemble de résultats, ce qui se produit après la requête principale.
John Hunt
236
SELECT varchar_col
FROMtableGROUPBY varchar_col
HAVING COUNT(*)>1;
Supérieur à la réponse de @ levik car il n'ajoute pas de colonne supplémentaire. Le rend utile pour une utilisation avec IN()/ NOT IN().
wmassingham
172
SELECT*FROM mytable mto
WHEREEXISTS(SELECT1FROM mytable mti
WHERE mti.varchar_column = mto.varchar_column
LIMIT 1,1)
Cette requête renvoie des enregistrements complets, pas seulement des enregistrements distincts varchar_column.
Cette requête n'utilise pas COUNT(*). S'il y a beaucoup de doublons, COUNT(*)coûte cher et que vous n'avez pas besoin du tout COUNT(*), il vous suffit de savoir s'il y a deux lignes de même valeur.
varchar_columnBien entendu, avoir un index accélérera considérablement cette requête.
Très bien. J'ai ajouté ORDER BY varchar_column DESCà la fin de la requête.
trante
8
Cela devrait être la réponse acceptée, car GROUP BYet HAVINGne renvoie qu'un seul des doublons possibles. En outre, les performances avec un champ indexé au lieu de COUNT(*), et la possibilité ORDER BYde regrouper les enregistrements en double.
Rémi Breton
1
Comme indiqué dans les commentaires ci-dessus, cette requête vous permet de répertorier toutes les lignes dupliquées. Très utile.
TryHarder
4
En regardant cela, je ne comprends pas du tout comment cela fonctionnerait. La condition interne ne sera-t-elle pas toujours vraie car toute ligne de la table externe sera également disponible dans la table interne et donc chaque ligne correspondra au moins toujours à elle-même? J'ai essayé la requête et obtenu le résultat que je soupçonnais - chaque ligne est revenue. Mais avec tant de votes positifs, je doute moi-même. La requête interne ne manque-t-elle pas quelque chose comme "AND mto.id <> mti.id"? Cela fonctionne pour moi lorsque j'ajoute cela.
Clox
2
@Quassnoi Très bien. J'ai essayé de le mettre sur sqlfiddle mais j'ai abandonné depuis que chaque requête que j'essaie d'exécuter, à part la création du schéma, arrive à expiration. J'ai compris que la simple suppression de "EXISTS" fait également fonctionner correctement la requête pour moi.
Clox
144
À partir de la réponse de levik pour obtenir les ID des lignes en double, vous pouvez le faire GROUP_CONCATsi votre serveur le prend en charge (cela renverra une liste d'ID séparés par des virgules).
SELECT GROUP_CONCAT(id), name, COUNT(*) c FROM documents GROUPBY name HAVING c >1;
Tout ce temps sans connaître GROUP_CONCAT ()! très très utile.
aesede
Vraiment apprécié Matt. C'est vraiment utile! Pour ceux qui essaient de mettre à jour dans phpmyadmin si vous laissez l'identifiant avec la fonction comme ceci: SELECT id, GROUP_CONCAT(id), name, COUNT(*) c [...]il permet la modification en ligne et il devrait mettre à jour toutes les lignes impliquées (ou au moins la première correspondante), mais malheureusement, la modification génère une erreur Javascript. ..
Armfoot
Comment calculeriez-vous alors combien d'ID sont sujets à duplication?
CMCDragonkai
2
Comment puis-je ne pas regrouper tous les ID, mais plutôt les répertorier du premier au dernier; avec toutes leurs valeurs respectives dans les colonnes à côté d'eux? Ainsi, au lieu de le regrouper, il affiche simplement l'ID 1 et sa valeur, l'ID 2 et sa valeur. MÊME si les valeurs de l'ID sont identiques.
MailBlade
1
Réponse extrêmement utile, cela devrait être top pour que plus de gens la voient. Je me souviens de la peine que j'ai éprouvée à créer de telles listes, et elles étaient disponibles tout le temps en tant que commande.
John
13
En supposant que votre table est nommée TableABC et la colonne que vous souhaitez est Col et la clé primaire de T1 est Key.
SELECT a.Key, b.Key, a.Col
FROM TableABC a, TableABC b
WHERE a.Col = b.Col
AND a.Key<> b.Key
L'avantage de cette approche sur la réponse ci-dessus est qu'elle donne la clé.
+1 Parce que c'est pratique. Cependant, ironiquement, le résultat lui-même contient des doublons (il répertorie a et b, puis b et a.)
Fabien Snauwaert
2
@FabienSnauwaert Vous pouvez vous débarrasser de certains des doublons en comparant moins que (ou plus que)
Michael
@TechTravelThink, votre réponse est très claire, merci pour cela, mais sur une grande table, cela prend du temps (environ 2mn sur plus de 20'000 entrées) et après afficher 25 premiers résultats, si je clique pour afficher le suivant, phpmyadmin affiche l'erreur "# 1052 - La colonne 'id' dans la clause de commande est ambiguë "
bcag2
12
SELECT*FROM`dps`WHERE pid IN(SELECT pid FROM`dps`GROUPBY pid HAVING COUNT(pid)>1)
FYI - Vous voudrez «sélectionner un somecol distinct ..» s'il existe un potentiel pour plus d'un enregistrement en double, sinon les résultats contiendront des doublons des lignes dupliquées trouvées.
Drew
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
Remplacez la ville par votre table. Remplacez le nom par le nom de votre champ
Pour aller plus loin dans la réponse de @ maxyfc , j'avais besoin de trouver toutes les lignes renvoyées avec les valeurs en double, afin de pouvoir les modifier dans MySQL Workbench :
SELECT*FROMtableWHERE field IN(SELECT field FROMtableGROUPBY field HAVING count(*)>1)ORDERBY field
J'ai vu le résultat ci-dessus et la requête fonctionnera bien si vous devez vérifier la valeur d'une seule colonne qui est en double. Par exemple, e-mail.
Mais si vous avez besoin de vérifier avec plus de colonnes et que vous souhaitez vérifier la combinaison du résultat, cette requête fonctionnera correctement:
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)
Exactement ce qui était nécessaire! Voici ma requête, en vérifiant 3 champs pour les doublons: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
Je préfère utiliser des fonctions fenêtrées (MySQL 8.0+) pour trouver des doublons car je pouvais voir la ligne entière:
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
Il convient de noter que cela est insupportablement lent ou pourrait même ne pas se terminer si la colonne interrogée n'est pas indexée. Sinon, j'ai pu passer a.emailà a.*et obtenir tous les ID des lignes avec des doublons.
NobleUplift
@NobleUplift De quoi parlez-vous?
Michael
@Michael Eh bien, puisque cela fait trois ans, je ne peux pas tester sur quelle version de MySQL que j'utilisais, mais j'ai essayé cette même requête sur une base de données où la colonne que je sélectionnais n'avait pas d'index, donc ça a pris pas mal de temps quelques secondes pour terminer. Le changer pour SELECT DISTINCT a.*résolu presque instantanément.
NobleUplift
@NobleUplift Ah ok. Je peux comprendre que ce soit lent ... la partie qui m'inquiète est "pourrait même ne pas finir".
Michael
@Michael Je ne me souviens pas sur quelle table de notre système je devais exécuter cette requête, mais pour ceux avec quelques millions d'enregistrements, ils auraient probablement fini, mais en un temps si long que j'ai abandonné de voir quand cela finirait en fait.
NobleUplift
1
Pour supprimer les lignes en double avec plusieurs champs, annulez-les d'abord à la nouvelle clé unique qui est spécifiée pour les seules lignes distinctes, puis utilisez la commande "group by" pour supprimer les lignes en double avec la même nouvelle clé unique:
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;
Pourquoi ne pas utiliser CREATE TEMPORARY TABLE ...? Une petite explication de votre solution serait formidable.
maxhb
1
Une contribution très tardive ... au cas où cela aiderait quiconque à waaaaaay sur la ligne ... J'ai eu la tâche de trouver des paires de transactions correspondantes (en fait des deux côtés des transferts de compte à compte) dans une application bancaire, pour identifier celles étaient le «de» et le «à» pour chaque transaction de transfert entre comptes, nous nous sommes donc retrouvés avec ceci:
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;
Le résultat est que le DuplicateResultsTablefournit des lignes contenant des transactions correspondantes (c'est-à-dire en double), mais il fournit également les mêmes identifiants de transaction en sens inverse la deuxième fois qu'il correspond à la même paire, de sorte que l'extérieur SELECTest là pour regrouper par le premier ID de transaction, ce qui est fait en utilisant LEASTet GREATESTpour vous assurer que les deux transactionid sont toujours dans le même ordre dans les résultats, ce qui le rend sûr GROUPpar le premier, éliminant ainsi toutes les correspondances en double. Parcourez près d'un million de records et identifié plus de 12 000 matchs en un peu moins de 2 secondes. Bien sûr, le transactionid est l'indice principal, ce qui a vraiment aidé.
Réponses:
Faites un
SELECT
avec uneGROUP BY
clause. Disons que le nom est la colonne dans laquelle vous souhaitez trouver des doublons:Cela renverra un résultat avec la valeur du nom dans la première colonne et un nombre de fois que cette valeur apparaîtra dans la seconde.
la source
GROUP_CONCAT(id)
et il listera les identifiants. Voir ma réponse pour un exemple.ERROR: column "c" does not exist LINE 1
?la source
IN()
/NOT IN()
.Cette requête renvoie des enregistrements complets, pas seulement des enregistrements distincts
varchar_column
.Cette requête n'utilise pas
COUNT(*)
. S'il y a beaucoup de doublons,COUNT(*)
coûte cher et que vous n'avez pas besoin du toutCOUNT(*)
, il vous suffit de savoir s'il y a deux lignes de même valeur.varchar_column
Bien entendu, avoir un index accélérera considérablement cette requête.la source
ORDER BY varchar_column DESC
à la fin de la requête.GROUP BY
etHAVING
ne renvoie qu'un seul des doublons possibles. En outre, les performances avec un champ indexé au lieu deCOUNT(*)
, et la possibilitéORDER BY
de regrouper les enregistrements en double.À partir de la réponse de levik pour obtenir les ID des lignes en double, vous pouvez le faire
GROUP_CONCAT
si votre serveur le prend en charge (cela renverra une liste d'ID séparés par des virgules).la source
SELECT id, GROUP_CONCAT(id), name, COUNT(*) c [...]
il permet la modification en ligne et il devrait mettre à jour toutes les lignes impliquées (ou au moins la première correspondante), mais malheureusement, la modification génère une erreur Javascript. ..En supposant que votre table est nommée TableABC et la colonne que vous souhaitez est Col et la clé primaire de T1 est Key.
L'avantage de cette approche sur la réponse ci-dessus est qu'elle donne la clé.
la source
la source
Pour trouver combien d'enregistrements sont des doublons dans la colonne de nom dans Employé, la requête ci-dessous est utile;
la source
pour obtenir toutes les données contenant des doublons, j'ai utilisé ceci:
TableName = la table avec laquelle vous travaillez.
DupliactedData = les données dupliquées que vous recherchez.
la source
Ma dernière requête a incorporé ici quelques-unes des réponses qui ont aidé - en combinant group by, count & GROUP_CONCAT.
Cela fournit l'id des deux exemples (séparés par des virgules), le code à barres dont j'avais besoin et le nombre de doublons.
Modifiez le tableau et les colonnes en conséquence.
la source
Je ne vois aucune approche JOIN, qui a de nombreuses utilisations en termes de doublons.
Cette approche vous donne des résultats réels doublés.
la source
Remplacez la ville par votre table. Remplacez le nom par le nom de votre champ
la source
Pour aller plus loin dans la réponse de @ maxyfc , j'avais besoin de trouver toutes les lignes renvoyées avec les valeurs en double, afin de pouvoir les modifier dans MySQL Workbench :
la source
J'ai vu le résultat ci-dessus et la requête fonctionnera bien si vous devez vérifier la valeur d'une seule colonne qui est en double. Par exemple, e-mail.
Mais si vous avez besoin de vérifier avec plus de colonnes et que vous souhaitez vérifier la combinaison du résultat, cette requête fonctionnera correctement:
la source
SELECT COUNT(CONCAT(userid,event,datetime)) AS total, userid, event, datetime FROM mytable GROUP BY CONCAT(userid, event, datetime ) HAVING total>1
Je préfère utiliser des fonctions fenêtrées (MySQL 8.0+) pour trouver des doublons car je pouvais voir la ligne entière:
DB Fiddle Demo
la source
la source
Ce qui suit trouvera tous les product_id qui sont utilisés plus d'une fois. Vous obtenez un seul enregistrement pour chaque product_id.
Code tiré de: http://chandreshrana.blogspot.in/2014/12/find-duplicate-records-based-on-any.html
la source
la source
la source
a.email
àa.*
et obtenir tous les ID des lignes avec des doublons.SELECT DISTINCT a.*
résolu presque instantanément.Pour supprimer les lignes en double avec plusieurs champs, annulez-les d'abord à la nouvelle clé unique qui est spécifiée pour les seules lignes distinctes, puis utilisez la commande "group by" pour supprimer les lignes en double avec la même nouvelle clé unique:
la source
CREATE TEMPORARY TABLE ...
? Une petite explication de votre solution serait formidable.Une contribution très tardive ... au cas où cela aiderait quiconque à waaaaaay sur la ligne ... J'ai eu la tâche de trouver des paires de transactions correspondantes (en fait des deux côtés des transferts de compte à compte) dans une application bancaire, pour identifier celles étaient le «de» et le «à» pour chaque transaction de transfert entre comptes, nous nous sommes donc retrouvés avec ceci:
Le résultat est que le
DuplicateResultsTable
fournit des lignes contenant des transactions correspondantes (c'est-à-dire en double), mais il fournit également les mêmes identifiants de transaction en sens inverse la deuxième fois qu'il correspond à la même paire, de sorte que l'extérieurSELECT
est là pour regrouper par le premier ID de transaction, ce qui est fait en utilisantLEAST
etGREATEST
pour vous assurer que les deux transactionid sont toujours dans le même ordre dans les résultats, ce qui le rend sûrGROUP
par le premier, éliminant ainsi toutes les correspondances en double. Parcourez près d'un million de records et identifié plus de 12 000 matchs en un peu moins de 2 secondes. Bien sûr, le transactionid est l'indice principal, ce qui a vraiment aidé.la source
la source
la source
Si vous souhaitez supprimer l'utilisation en double
DISTINCT
Sinon, utilisez cette requête:
SELECT users.*,COUNT(user_ID) as user FROM users GROUP BY user_name HAVING user > 1;
la source
Essayez d'utiliser cette requête:
la source