J'ai inséré entre deux tables les champs A, B, C, D, croyant avoir créé un index unique sur A, B, C, D pour éviter les doublons. Cependant j'ai en quelque sorte simplement fait un index normal sur ceux-ci. Des doublons ont donc été insérés. C'est une table record de 20 millions.
Si je change mon index existant de normal à unique ou simplement ajoute un nouvel index unique pour A, B, C, D, les doublons seront-ils supprimés ou l'ajout échouera-t-il car des enregistrements uniques existent? Je le testerais pourtant, il s'agit de disques de 30 mil et je ne souhaite ni gâcher la table ni la dupliquer.
Si vous avez des doublons dans votre table et que vous utilisez
ALTER TABLE mytable ADD UNIQUE INDEX myindex (A, B, C, D);
la requête échouera avec l'erreur 1062 (clé en double).
Mais si vous utilisez IGNORE
-- (only works before MySQL 5.7.4)
ALTER IGNORE TABLE mytable ADD UNIQUE INDEX myindex (A, B, C, D);
les doublons seront supprimés. Mais la documentation ne précise pas quelle ligne sera conservée:
IGNORE
est une extension MySQL du SQL standard. Il contrôle commentALTER TABLE
fonctionne s'il y a des doublons sur des clés uniques dans la nouvelle table ou si des avertissements se produisent lorsque le mode strict est activé. SiIGNORE
n'est pas spécifié, la copie est abandonnée et annulée si des erreurs de clé en double se produisent. SiIGNORE
est spécifié, une seule ligne est utilisée pour les lignes avec doublons sur une clé unique. Les autres lignes en conflit sont supprimées. Les valeurs incorrectes sont tronquées à la valeur acceptable correspondante la plus proche.
Depuis MySQL 5.7.4, la clause IGNORE pour ALTER TABLE est supprimée et son utilisation génère une erreur.
Si votre version est 5.7.4 ou supérieure - vous pouvez:
INSERT IGNORE
(qui est toujours disponible).CREATE TABLE tmp_data SELECT * FROM mytable;
TRUNCATE TABLE mytable;
ALTER TABLE mytable ADD UNIQUE INDEX myindex (A, B, C, D);
INSERT IGNORE INTO mytable SELECT * from tmp_data;
DROP TABLE tmp_data;
Si vous utilisez le modificateur
IGNORE
, les erreurs qui se produisent lors de l'exécution de l'instructionINSERT
sont ignorées. Par exemple, sansIGNORE
, une ligne qui duplique un indexUNIQUE
ouPRIMARY KEY
la valeur dans le tableau provoque une erreur de clé en double et l'instruction est abandonnée. AvecIGNORE
, la ligne est supprimée et aucune erreur ne se produit. Les erreurs ignorées génèrent à la place des avertissements.
Voir aussi: INSERT ... SELECT Syntax et Comparaison du mot-clé IGNORE et du mode SQL strict
si vous pensez qu'il y aura des doublons, l'ajout de l'index unique échouera. vérifiez d'abord les doublons:
select * from
(select a,b,c,d,count(*) as n from table_name group by a,b,c,d) x
where x.n > 1
Cela peut être une requête coûteuse sur 20 millions de lignes, mais vous obtiendrez toutes les clés en double qui vous empêcheront d'ajouter l'index principal. Vous pouvez le diviser en morceaux plus petits si vous faites un où dans la sous-requête: where a='some_value'
Pour les enregistrements récupérés, vous devrez modifier quelque chose pour rendre les lignes uniques. Si cela est fait (la requête renvoie 0 lignes), vous devriez être sûr d'ajouter l'index principal.
Au lieu d'IGNORE, vous pouvez utiliser ON DUPLICATE KEY UPDATE, qui vous donnera le contrôle sur les valeurs qui doivent prévaloir.
Pour répondre à votre question, l'ajout d'une contrainte UNIQUE
sur une colonne contenant des valeurs en double génère une erreur.
Par exemple, vous pouvez essayer le script suivant:
CREATE TABLE `USER` (
`USER_ID` INT NOT NULL,
`USERNAME` VARCHAR(45) NOT NULL,
`NAME` VARCHAR(45) NULL,
PRIMARY KEY (`USER_ID`));
INSERT INTO USER VALUES(1,'Apple', 'woz'),(2,'Apple', 'jobs'),
(3,'google', 'sergey'),(4,'google', 'larry');
ALTER TABLE `USER`
ADD UNIQUE INDEX `USERNAME_UNIQUE` (`USERNAME` ASC);
/*
Operation failed: There was an error while applying the SQL script to the database.
ERROR 1062: Duplicate entry 'Apple' for key 'USERNAME_UNIQUE'
*/