Supprimer les lignes en double dans MySQL

375

J'ai une table avec les champs suivants:

id (Unique)
url (Unique)
title
company
site_id

Maintenant, je dois supprimer des lignes ayant le même title, company and site_id. Une façon de le faire sera d'utiliser le SQL suivant avec un script ( PHP):

SELECT title, site_id, location, id, count( * ) 
FROM jobs
GROUP BY site_id, company, title, location
HAVING count( * ) >1

Après avoir exécuté cette requête, je peux supprimer les doublons à l'aide d'un script côté serveur.

Mais, je veux savoir si cela ne peut être fait qu'en utilisant une requête SQL.

Chétan
la source
1
Question rapide: vous souhaitez toujours que le doublon (titre, société, site_id) n'existe pas? Si c'est le cas, je mettrais en place une contrainte dans la base de données pour que le titre, la société et le site_id soient uniques. Cela signifierait que vous n'auriez pas besoin d'un processus de nettoyage. Et cela ne prend qu'une seule ligne de SQL.
J.Polfer
1
Veuillez vous référer à ce lien de stackoverflow . Cela a fonctionné pour moi comme un charme.
Je peux recommander cette solution (publiée dans un autre fil): stackoverflow.com/a/4685232/195835
Simon East
Vous pouvez également vérifier cette réponse
Jose Rui Santos

Réponses:

607

Un moyen très simple de le faire est d'ajouter un UNIQUEindex sur les 3 colonnes. Lorsque vous écrivez la ALTERdéclaration, incluez le IGNOREmot - clé. Ainsi:

ALTER IGNORE TABLE jobs
ADD UNIQUE INDEX idx_name (site_id, title, company);

Cela supprimera toutes les lignes en double. Comme avantage supplémentaire, les futurs INSERTsdoublons seront des erreurs. Comme toujours, vous voudrez peut-être faire une sauvegarde avant d'exécuter quelque chose comme ça ...

Chris Henry
la source
8
Intéressant , mais les hypothèses que la clause IGNORE fait pour supprimer ces doublons est une préoccupation qui pourrait ne pas correspondre aux besoins. Des valeurs incorrectes tronquées à la correspondance acceptable la plus proche vous semblent bonnes?
OMG Ponies
75
Juste pour mémoire, si vous utilisez InnoDB, vous pouvez avoir un problème, il existe un bogue connu concernant l'utilisation d'ALTER IGNORE TABLE avec les bases de données InnoDB.
DarkMantis
27
Le bogue @DarkMantis mentionné ci-dessus et sa solution .
Jordan Arseno
42
Pour les tables InnoDB, exécutez d'abord la requête suivante:set session old_alter_table=1;
shock_one
51
Ce n'est plus pris en charge dans 5.7.4, dev.mysql.com/doc/refman/5.7/en/alter-table.html
Ray Baxter
180

Si vous ne souhaitez pas modifier les propriétés de la colonne, vous pouvez utiliser la requête ci-dessous.

Étant donné que vous avez une colonne qui a des ID uniques (par exemple, des auto_incrementcolonnes), vous pouvez l'utiliser pour supprimer les doublons:

DELETE `a`
FROM
    `jobs` AS `a`,
    `jobs` AS `b`
WHERE
    -- IMPORTANT: Ensures one version remains
    -- Change "ID" to your unique column's name
    `a`.`ID` < `b`.`ID`

    -- Any duplicates you want to check for
    AND (`a`.`title` = `b`.`title` OR `a`.`title` IS NULL AND `b`.`title` IS NULL)
    AND (`a`.`company` = `b`.`company` OR `a`.`company` IS NULL AND `b`.`company` IS NULL)
    AND (`a`.`site_id` = `b`.`site_id` OR `a`.`site_id` IS NULL AND `b`.`site_id` IS NULL);

Dans MySQL, vous pouvez le simplifier encore plus avec l' opérateur égal NULL-safe (alias "opérateur de vaisseau spatial" ):

DELETE `a`
FROM
    `jobs` AS `a`,
    `jobs` AS `b`
WHERE
    -- IMPORTANT: Ensures one version remains
    -- Change "ID" to your unique column's name
    `a`.`ID` < `b`.`ID`

    -- Any duplicates you want to check for
    AND `a`.`title` <=> `b`.`title`
    AND `a`.`company` <=> `b`.`company`
    AND `a`.`site_id` <=> `b`.`site_id`;
rehriff
la source
3
cette solution ne fonctionne pas correctement, j'ai essayé de faire des enregistrements en double et elle fait quelque chose comme (20 lignes affectées) mais si vous l'exécutez à nouveau, elle vous montrera (4 lignes affectées) et ainsi de suite jusqu'à ce que vous atteigniez (0 lignes affectées) ce qui est un peu suspect et voici ce qui fonctionne le mieux pour moi, c'est presque la même chose mais cela fonctionne en une seule fois, j'ai édité la solution
Nassim
1
@Nassim: Vous devez faire quelque chose de différent de cette réponse car cela fonctionne parfaitement pour moi (dans MySQL).
Lawrence Dol
3
Pour toute personne confuse comme moi, les termes de comparaison NULL sont nécessaires car NULL n'est pas égal à NULL dans MySQL. S'il est garanti que les colonnes pertinentes ne sont pas NULL, vous pouvez ignorer ces termes.
Ian
3
Oui, la réponse acceptée n'est plus valide, car MYSQL 5.7 devrait donc être vraiment la réponse acceptée car elle est universelle et ne nécessite pas non plus de création de table temporaire.
that-ben
1
TRÈS LENT s'il y a BEAUCOUP de copies d'un enregistrement donné (par exemple 100 à réduire à 1), et de nombreux enregistrements avec cette condition. Recommandez plutôt stackoverflow.com/a/4685232/199364 . À mon humble avis, utilisez TOUJOURS l'approche liée; c'est une technique intrinsèquement plus rapide.
ToolmakerSteve
78

MySQL a des restrictions sur la référence à la table que vous supprimez. Vous pouvez contourner cela avec une table temporaire, comme:

create temporary table tmpTable (id int);

insert  into tmpTable
        (id)
select  id
from    YourTable yt
where   exists
        (
        select  *
        from    YourTabe yt2
        where   yt2.title = yt.title
                and yt2.company = yt.company
                and yt2.site_id = yt.site_id
                and yt2.id > yt.id
        );

delete  
from    YourTable
where   ID in (select id from tmpTable);

D'après la suggestion de Kostanos dans les commentaires:
La seule requête lente ci-dessus est DELETE, pour les cas où vous avez une très grande base de données. Cette requête pourrait être plus rapide:

DELETE FROM YourTable USING YourTable, tmpTable WHERE YourTable.id=tmpTable.id
Andomar
la source
3
@andomar, cela fonctionne très bien sauf lorsque l'un des champs de la clause where contient des valeurs nulles. Exemple: sqlfiddle.com/#!2/983f3/1
un codeur
1
L'insertion SQL est-elle coûteuse? Je me demande parce que ça arrive à expiration dans ma base de données MySQL.
Cassio
4
La seule requête lente ici c'est la SUPPRIMER, au cas où vous avez une grande base de données. Cette requête pourrait être plus rapide:DELETE FROM YourTable USING YourTable, tmpTable WHERE YourTable.id=tmpTable.id
Kostanos
@Kostanos Non seulement DELETE, mais aussi INSERTà la table temporaire, cela m'a pris beaucoup de temps. Un index pour la table tmp pourrait donc aider beaucoup create index tmpTable_id_index on tmpTable (id), du moins pour moi.
Jiezhi.G
1
Si vos tables sont grandes, cela vaut la peine d'ajouter un index avec: -create temporary table tmpTable (id int, PRIMARY KEY (id));
Dallas Clarke
44

Si l' IGNOREinstruction ne fonctionne pas comme dans mon cas, vous pouvez utiliser l'instruction ci-dessous:

CREATE TABLE your_table_deduped LIKE your_table;


INSERT your_table_deduped
SELECT *
FROM your_table
GROUP BY index1_id,
         index2_id;

RENAME TABLE your_table TO your_table_with_dupes;

RENAME TABLE your_table_deduped TO your_table;

#OPTIONAL
ALTER TABLE `your_table` ADD UNIQUE `unique_index` (`index1_id`, `index2_id`);

#OPTIONAL
DROP TABLE your_table_with_dupes;
Kamil
la source
1
fonctionne très bien si vous avez un paramètre innoDB avec une contrainte de clé étrangère.
magdmartin
@magdmartin, mais les contraintes étrangères n'empêcheront-elles pas la suppression de la table?
Basilevs
1
La déclaration IGNORE n'a pas fonctionné pour moi et cela a très bien fonctionné pour dédoubler 5 millions d'enregistrements. À votre santé.
Mauvis Ledford
32

La suppression des doublons sur les tables MySQL est un problème courant, c'est généralement le résultat d'une contrainte manquante pour éviter ces doublons à l'avance. Mais ce problème commun s'accompagne généralement de besoins spécifiques ... qui nécessitent des approches spécifiques. L'approche doit être différente selon, par exemple, la taille des données, l'entrée dupliquée qui doit être conservée (généralement la première ou la dernière), s'il y a des index à conserver ou si nous voulons effectuer des action sur les données dupliquées.

Il existe également certaines spécificités sur MySQL lui-même, comme le fait de ne pas pouvoir référencer la même table sur une cause FROM lors de l'exécution d'une mise à jour de table (cela soulèvera l'erreur MySQL # 1093). Cette limitation peut être surmontée en utilisant une requête interne avec une table temporaire (comme suggéré dans certaines approches ci-dessus). Mais cette requête interne ne fonctionnera pas particulièrement bien lorsqu'il s'agit de sources de données volumineuses.

Cependant, il existe une meilleure approche pour supprimer les doublons, à la fois efficace et fiable, et qui peut être facilement adaptée à différents besoins.

L'idée générale est de créer une nouvelle table temporaire, en ajoutant généralement une contrainte unique pour éviter d'autres doublons, et d'insérer les données de votre ancienne table dans la nouvelle, tout en prenant soin des doublons. Cette approche repose sur des requêtes MySQL INSERT simples, crée une nouvelle contrainte pour éviter d'autres doublons, et ignore la nécessité d'utiliser une requête interne pour rechercher des doublons et une table temporaire qui doit être conservée en mémoire (s'adaptant ainsi également aux sources de Big Data).

Voilà comment cela peut être réalisé. Étant donné que nous avons un employé de table , avec les colonnes suivantes:

employee (id, first_name, last_name, start_date, ssn)

Afin de supprimer les lignes avec une colonne ssn en double et en ne conservant que la première entrée trouvée, le processus suivant peut être suivi:

-- create a new tmp_eployee table
CREATE TABLE tmp_employee LIKE employee;

-- add a unique constraint
ALTER TABLE tmp_employee ADD UNIQUE(ssn);

-- scan over the employee table to insert employee entries
INSERT IGNORE INTO tmp_employee SELECT * FROM employee ORDER BY id;

-- rename tables
RENAME TABLE employee TO backup_employee, tmp_employee TO employee;

Explication technique

  • La ligne # 1 crée une nouvelle table tmp_eployee avec exactement la même structure que la table des employés
  • La ligne # 2 ajoute une contrainte UNIQUE à la nouvelle table tmp_eployee pour éviter tout doublon supplémentaire
  • La ligne n ° 3 parcourt la table des employés d' origine par identifiant, en insérant de nouvelles entrées d'employé dans la nouvelle table tmp_eployee , tout en ignorant les entrées en double
  • La ligne # 4 renomme les tables, de sorte que la nouvelle table des employés contienne toutes les entrées sans les doublons, et une copie de sauvegarde des anciennes données est conservée dans la table backup_employee

En utilisant cette approche, 1,6M de registres ont été convertis en 6k en moins de 200s.

Chetan , en suivant ce processus, vous pouvez supprimer rapidement et facilement tous vos doublons et créer une contrainte UNIQUE en exécutant:

CREATE TABLE tmp_jobs LIKE jobs;

ALTER TABLE tmp_jobs ADD UNIQUE(site_id, title, company);

INSERT IGNORE INTO tmp_jobs SELECT * FROM jobs ORDER BY id;

RENAME TABLE jobs TO backup_jobs, tmp_jobs TO jobs;

Bien sûr, ce processus peut être modifié pour l'adapter aux différents besoins lors de la suppression des doublons. Quelques exemples suivent.

✔ Variation pour conserver la dernière entrée au lieu de la première

Parfois, nous devons conserver la dernière entrée dupliquée au lieu de la première.

CREATE TABLE tmp_employee LIKE employee;

ALTER TABLE tmp_employee ADD UNIQUE(ssn);

INSERT IGNORE INTO tmp_employee SELECT * FROM employee ORDER BY id DESC;

RENAME TABLE employee TO backup_employee, tmp_employee TO employee;
  • Sur la ligne # 3, la clause ORDER BY id DESC fait que les derniers ID obtiennent la priorité sur les autres

✔ Variation pour effectuer certaines tâches sur les doublons, par exemple en comptant les doublons trouvés

Parfois, nous devons effectuer un traitement supplémentaire sur les entrées dupliquées trouvées (par exemple, en comptant les doublons).

CREATE TABLE tmp_employee LIKE employee;

ALTER TABLE tmp_employee ADD UNIQUE(ssn);

ALTER TABLE tmp_employee ADD COLUMN n_duplicates INT DEFAULT 0;

INSERT INTO tmp_employee SELECT * FROM employee ORDER BY id ON DUPLICATE KEY UPDATE n_duplicates=n_duplicates+1;

RENAME TABLE employee TO backup_employee, tmp_employee TO employee;
  • Sur la ligne # 3, une nouvelle colonne n_duplicates est créée
  • Sur la ligne # 4, la requête INSERT INTO ... ON DUPLICATE KEY UPDATE est utilisée pour effectuer une mise à jour supplémentaire lorsqu'un doublon est trouvé (dans ce cas, l'augmentation d'un compteur) La requête INSERT INTO ... ON DUPLICATE KEY UPDATE peut être utilisé pour effectuer différents types de mises à jour pour les doublons trouvés.

✔ Variation pour régénérer l'identifiant de champ auto-incrémental

Parfois, nous utilisons un champ auto-incrémentiel et, afin de garder l'index aussi compact que possible, nous pouvons profiter de la suppression des doublons pour régénérer le champ auto-incrémental dans la nouvelle table temporaire.

CREATE TABLE tmp_employee LIKE employee;

ALTER TABLE tmp_employee ADD UNIQUE(ssn);

INSERT IGNORE INTO tmp_employee SELECT (first_name, last_name, start_date, ssn) FROM employee ORDER BY id;

RENAME TABLE employee TO backup_employee, tmp_employee TO employee;
  • Sur la ligne n ° 3, au lieu de sélectionner tous les champs de la table, le champ id est ignoré afin que le moteur de base de données en génère automatiquement un nouveau

✔ Autres variations

De nombreuses autres modifications sont également réalisables en fonction du comportement souhaité. À titre d'exemple, les requêtes suivantes utiliseront une deuxième table temporaire pour, outre 1) conserver la dernière entrée au lieu de la première; et 2) augmenter le compteur des doublons trouvés; également 3) régénérer l'identifiant de champ auto-incrémentiel tout en conservant l'ordre d'entrée tel qu'il était sur les anciennes données.

CREATE TABLE tmp_employee LIKE employee;

ALTER TABLE tmp_employee ADD UNIQUE(ssn);

ALTER TABLE tmp_employee ADD COLUMN n_duplicates INT DEFAULT 0;

INSERT INTO tmp_employee SELECT * FROM employee ORDER BY id DESC ON DUPLICATE KEY UPDATE n_duplicates=n_duplicates+1;

CREATE TABLE tmp_employee2 LIKE tmp_employee;

INSERT INTO tmp_employee2 SELECT (first_name, last_name, start_date, ssn) FROM tmp_employee ORDER BY id;

DROP TABLE tmp_employee;

RENAME TABLE employee TO backup_employee, tmp_employee2 TO employee;
César Revert-Gomar
la source
27

Il existe une autre solution:

DELETE t1 FROM my_table t1, my_table t2 WHERE t1.id < t2.id AND t1.my_field = t2.my_field AND t1.my_field_2 = t2.my_field_2 AND ...
Mostafa -T
la source
4
En quoi est-ce différent de la réponse de @ rehriff, qu'il a soumise 6 mois plus tôt?
Lawrence Dol
@ LawrenceDol Je suppose que c'est un peu plus lisible et aussi je pense que sa réponse n'était pas la même au moment où j'ai répondu et je pense que sa réponse a été modifiée.
Mostafa -T
1
hmm. Cela me prend trop de temps alors que le nombre de disques n'était pas gros!
SuB
8

si vous avez une grande table avec un grand nombre d'enregistrements, les solutions ci-dessus ne fonctionneront pas ou ne prendront pas trop de temps. Ensuite, nous avons une solution différente

-- Create temporary table

CREATE TABLE temp_table LIKE table1;

-- Add constraint
ALTER TABLE temp_table ADD UNIQUE(title, company,site_id);

-- Copy data
INSERT IGNORE INTO temp_table SELECT * FROM table1;

-- Rename and drop
RENAME TABLE table1 TO old_table1, temp_table TO table1;
DROP TABLE old_table1;
faisalbhagat
la source
6

J'ai ce snipet de requête pour SQLServer mais je pense qu'il peut être utilisé dans d'autres SGBD avec peu de changements:

DELETE
FROM Table
WHERE Table.idTable IN  (  
    SELECT MAX(idTable)
    FROM idTable
    GROUP BY field1, field2, field3
    HAVING COUNT(*) > 1)

J'ai oublié de vous dire que cette requête ne supprime pas la ligne avec l'ID le plus bas des lignes dupliquées. Si cela fonctionne pour vous, essayez cette requête:

DELETE
FROM jobs
WHERE jobs.id IN  (  
    SELECT MAX(id)
    FROM jobs
    GROUP BY site_id, company, title, location
    HAVING COUNT(*) > 1)
Eduardo Rascon
la source
Cela ne fonctionnera pas s'il y a plus de deux doublons d'un groupe.
OMG Ponies
11
Malheureusement, MySQL ne vous permet pas de sélectionner dans la table que vous supprimezERROR 1093: You can't specify target table 'Table' for update in FROM clause
Andomar
1
Pour résoudre l' "You can't specify target table 'Table' for update in FROM..."erreur, utilisez: DELETE FROM Table WHERE Table.idTable IN ( SELECT MAX(idTable) FROM (SELECT * FROM idTable) AS tmp GROUP BY field1, field2, field3 HAVING COUNT(*) > 1)qui force MySQL à créer une table temporellement. Cependant, il est très lent dans les grands ensembles de données ... dans de tels cas, je recommanderai le code d'Andomar, qui est beaucoup plus rapide.
lepe
6

Le moyen le plus rapide consiste à insérer des lignes distinctes dans une table temporaire. En utilisant la suppression, il m'a fallu quelques heures pour supprimer les doublons d'une table de 8 millions de lignes. En utilisant insert et distinct, cela n'a pris que 13 minutes.

CREATE TABLE tempTableName LIKE tableName;  
CREATE INDEX ix_all_id ON tableName(cellId,attributeId,entityRowId,value);  
INSERT INTO tempTableName(cellId,attributeId,entityRowId,value) SELECT DISTINCT cellId,attributeId,entityRowId,value FROM tableName;  
TRUNCATE TABLE tableName;
INSERT INTO tableName SELECT * FROM tempTableName; 
DROP TABLE tempTableName;  
Nav
la source
1
Votre 4e ligne devrait dire TRUNCATE TABLE tableNameet 5e ligne devrait direINSERT INTO tableName SELECT * FROM tempTableName;
Sana
5

Une solution simple à comprendre et qui fonctionne sans clé primaire:

1) ajouter une nouvelle colonne booléenne

alter table mytable add tokeep boolean;

2) ajouter une contrainte sur les colonnes dupliquées ET la nouvelle colonne

alter table mytable add constraint preventdupe unique (mycol1, mycol2, tokeep);

3) définissez la colonne booléenne sur true. Cela ne réussira que sur l'une des lignes dupliquées en raison de la nouvelle contrainte

update ignore mytable set tokeep = true;

4) supprimer les lignes qui n'ont pas été marquées comme étant conservées

delete from mytable where tokeep is null;

5) déposez la colonne ajoutée

alter table mytable drop tokeep;

Je vous suggère de conserver la contrainte que vous avez ajoutée, afin d'éviter de nouveaux doublons à l'avenir.

xtian
la source
1
Cela a très bien fonctionné dans mysql 5.7 où la solution acceptée ne fonctionne plus
Robin31
5

Supprimer les lignes en double à l'aide de l'instruction DELETE JOIN MySQL vous fournit l'instruction DELETE JOIN que vous pouvez utiliser pour supprimer rapidement les lignes en double.

L'instruction suivante supprime les lignes en double et conserve l'ID le plus élevé:

DELETE t1 FROM contacts t1
    INNER JOIN
contacts t2 WHERE
t1.id < t2.id AND t1.email = t2.email;
Saad Mirza
la source
5

J'ai trouvé un moyen simple. (garder le dernier)

DELETE t1 FROM tablename t1 INNER JOIN tablename t2 
WHERE t1.id < t2.id AND t1.column1 = t2.column1 AND t1.column2 = t2.column2;
Rico Nguyen
la source
4

Simple et rapide pour tous les cas:

CREATE TEMPORARY TABLE IF NOT EXISTS _temp_duplicates AS (SELECT dub.id FROM table_with_duplications dub GROUP BY dub.field_must_be_uniq_1, dub.field_must_be_uniq_2 HAVING COUNT(*)  > 1);

DELETE FROM table_with_duplications WHERE id IN (SELECT id FROM _temp_duplicates);
artemiuz
la source
Code d'erreur: 1055. L'expression n ° 2 de la liste SELECT n'est pas dans la clause GROUP BY et contient la colonne non agrégée «dub.id» qui ne dépend pas fonctionnellement des colonnes de la clause GROUP BY; cela est incompatible avec sql_mode = only_full_group_by
Swoogan
vous pouvez désactiver le "contrôle dur" avec sql_mode, voir stackoverflow.com/questions/23921117/disable-only-full-group-by
artemiuz
4

Cela supprimera les lignes en double avec les mêmes valeurs pour le titre, la société et le site. La première occurrence sera conservée et tous les doublons seront supprimés

DELETE t1 FROM tablename t1
INNER JOIN tablename t2 
WHERE 
    t1.id < t2.id AND
    t1.title = t2.title AND
    t1.company=t2.company AND
    t1.site_ID=t2.site_ID;
Dhrumil Panchal
la source
c'est lent (5w + lignes, délai d'attente de verrouillage) mais a fonctionné
yurenchen
3

Je continue à visiter cette page chaque fois que je google "supprime les doublons de mysql" mais pour mes solutions theIGNORE ne fonctionnent pas car j'ai des tables mysql InnoDB

ce code fonctionne mieux à tout moment

CREATE TABLE tableToclean_temp LIKE tableToclean;
ALTER TABLE tableToclean_temp ADD UNIQUE INDEX (fontsinuse_id);
INSERT IGNORE INTO tableToclean_temp SELECT * FROM tableToclean;
DROP TABLE tableToclean;
RENAME TABLE tableToclean_temp TO tableToclean;

tableToclean = le nom de la table que vous devez nettoyer

tableToclean_temp = une table temporaire créée et supprimée

Francesco
la source
2

Cette solution déplacera les doublons dans une table et les uniques dans une autre .

-- speed up creating uniques table if dealing with many rows
CREATE INDEX temp_idx ON jobs(site_id, company, title, location);

-- create the table with unique rows
INSERT jobs_uniques SELECT * FROM
    (
    SELECT * 
    FROM jobs
    GROUP BY site_id, company, title, location
    HAVING count(1) > 1
    UNION
    SELECT *
    FROM jobs
    GROUP BY site_id, company, title, location
    HAVING count(1) = 1
) x

-- create the table with duplicate rows
INSERT jobs_dupes 
SELECT * 
FROM jobs
WHERE id NOT IN
(SELECT id FROM jobs_uniques)

-- confirm the difference between uniques and dupes tables
SELECT COUNT(1)
AS jobs, 
(SELECT COUNT(1) FROM jobs_dupes) + (SELECT COUNT(1) FROM jobs_uniques)
AS sum
FROM jobs
Anthony Vipond
la source
Pourquoi avez-vous choisi le syndicat et pas seulement SELECT * FROM jobs GROUP BY site_id, company, title, location?
timctran
2

Depuis la version 8.0 (2018), MySQL prend enfin en charge les fonctions de fenêtre .

Les fonctions des fenêtres sont à la fois pratiques et efficaces. Voici une solution qui montre comment les utiliser pour résoudre cette tâche.

Dans une sous-requête, nous pouvons utiliser ROW_NUMBER()pour attribuer une position à chaque enregistrement de la table dans des column1/column2groupes, classés par id. S'il n'y a pas de doublons, l'enregistrement obtiendra le numéro de ligne 1. S'il existe des doublons, ils seront numérotés par ordre croissant id(à partir de 1).

Une fois les enregistrements correctement numérotés dans la sous-requête, la requête externe supprime simplement tous les enregistrements dont le numéro de ligne n'est pas 1.

Requete :

DELETE FROM tablename
WHERE id IN (
    SELECT id
    FROM (
        SELECT 
            id, 
            ROW_NUMBER() OVER(PARTITION BY column1, column2 ORDER BY id) rn
        FROM output
    ) t
    WHERE rn > 1
)
GMB
la source
1

Pour supprimer l'enregistrement en double dans une table.

delete from job s 
where rowid < any 
(select rowid from job k 
where s.site_id = k.site_id and 
s.title = k.title and 
s.company = k.company);

ou

delete from job s 
where rowid not in 
(select max(rowid) from job k 
where s.site_id = k.site_id and
s.title = k.title and 
s.company = k.company);
Arun Solomon
la source
1
-- Here is what I used, and it works:
create table temp_table like my_table;
-- t_id is my unique column
insert into temp_table (id) select id from my_table GROUP by t_id;
delete from my_table where id not in (select id from temp_table);
drop table temp_table;
Duy Hoang
la source
0

Afin de dupliquer des enregistrements avec des colonnes uniques, par exemple COL1, COL2, COL3 ne doivent pas être répliqués (supposons que nous ayons omis 3 colonnes uniques dans la structure du tableau et que plusieurs entrées en double aient été introduites dans le tableau)

DROP TABLE TABLE_NAME_copy;
CREATE TABLE TABLE_NAME_copy LIKE TABLE_NAME;
INSERT INTO TABLE_NAME_copy
SELECT * FROM TABLE_NAME
GROUP BY COLUMN1, COLUMN2, COLUMN3; 
DROP TABLE TABLE_NAME;
ALTER TABLE TABLE_NAME_copy RENAME TO TABLE_NAME;

L'espoir aidera le dev.

Abdul Rehman
la source
0

TL; TR;

Un tutoriel largement décrit pour résoudre ce problème peut être trouvé sur le site mysqltutorial.org :

Comment supprimer des lignes en double dans MySQL

Il est très clairement montré comment supprimer les lignes en double de trois manières différentes :

A) Utilisation de l' DELETE JOINinstruction

B) Utilisation d'une table intermédiaire

C) Utilisation de la ROW_NUMBER()fonction

J'espère que cela aidera quelqu'un.

simhumileco
la source
0

J'ai une table qui oublie d'ajouter une clé primaire dans la ligne id. Bien qu'il ait auto_increment sur l'id. Mais un jour, une chose rejoue le journal bin mysql sur la base de données qui insère des lignes en double.

Je supprime la ligne en double par

  1. sélectionner les lignes en double uniques et les exporter

select T1.* from table_name T1 inner join (select count(*) as c,id from table_name group by id) T2 on T1.id = T2.id where T2.c > 1 group by T1.id;

  1. supprimer les lignes en double par id

  2. insérez la ligne à partir des données exportées.

  3. Ajoutez ensuite la clé primaire sur id

Kris Roofe
la source
-2

J'aime être un peu plus précis sur les enregistrements que je supprime alors voici ma solution:

delete
from jobs c1
where not c1.location = 'Paris'
and  c1.site_id > 64218
and exists 
(  
select * from jobs c2 
where c2.site_id = c1.site_id
and   c2.company = c1.company
and   c2.location = c1.location
and   c2.title = c1.title
and   c2.site_id > 63412
and   c2.site_id < 64219
)
Michael Tel
la source
-4

Vous pouvez facilement supprimer les enregistrements en double de ce code.

$qry = mysql_query("SELECT * from cities");
while($qry_row = mysql_fetch_array($qry))
{
$qry2 = mysql_query("SELECT * from cities2 where city = '".$qry_row['city']."'");

if(mysql_num_rows($qry2) > 1){
    while($row = mysql_fetch_array($qry2)){
        $city_arry[] = $row;

        }

    $total = sizeof($city_arry) - 1;
        for($i=1; $i<=$total; $i++){


            mysql_query( "delete from cities2 where town_id = '".$city_arry[$i][0]."'");

            }
    }
    //exit;
}
Syed Amir Bukhari
la source
3
C'est très mauvais. Les tâches de base de données doivent être effectuées dans la base de données, où elles sont beaucoup plus rapides, au lieu d'envoyer constamment des données entre php / mysql car vous en connaissez une meilleure que l'autre.
Max
-4

J'ai dû le faire avec des champs de texte et suis tombé sur la limite de 100 octets sur l'index.

J'ai résolu cela en ajoutant une colonne, en faisant un hachage md5 des champs et en faisant l'alter.

ALTER TABLE table ADD `merged` VARCHAR( 40 ) NOT NULL ;
UPDATE TABLE SET merged` = MD5(CONCAT(`col1`, `col2`, `col3`))
ALTER IGNORE TABLE table ADD UNIQUE INDEX idx_name (`merged`);
Sunil
la source