J'ai des champs uniques id
et email
. Les e-mails sont dupliqués. Je veux seulement conserver une adresse électronique de tous les doublons, mais avec la dernière id
(le dernier enregistrement inséré).
Comment puis-je atteindre cet objectif?
Imaginez que votre table test
contienne les données suivantes:
select id, email
from test;
ID EMAIL
---------------------- --------------------
1 aaa
2 bbb
3 ccc
4 bbb
5 ddd
6 eee
7 aaa
8 aaa
9 eee
Nous devons donc rechercher tous les courriels répétés et les supprimer tous, mais le dernier identifiant.
Dans ce cas, aaa
, bbb
et eee
sont répétés, nous voulons donc supprimer les identifiants 1, 7, 2 et 6.
Pour ce faire, nous devons d’abord trouver tous les courriels répétés:
select email
from test
group by email
having count(*) > 1;
EMAIL
--------------------
aaa
bbb
eee
Ensuite, à partir de cet ensemble de données, nous devons trouver le dernier identifiant pour chacun de ces courriels répétés:
select max(id) as lastId, email
from test
where email in (
select email
from test
group by email
having count(*) > 1
)
group by email;
LASTID EMAIL
---------------------- --------------------
8 aaa
4 bbb
9 eee
Enfin, nous pouvons maintenant supprimer tous ces courriels avec un identifiant plus petit que LASTID. La solution est donc:
delete test
from test
inner join (
select max(id) as lastId, email
from test
where email in (
select email
from test
group by email
having count(*) > 1
)
group by email
) duplic on duplic.email = test.email
where test.id < duplic.lastId;
MySql n'est pas installé sur cette machine pour le moment, mais devrait fonctionner
La suppression ci-dessus fonctionne, mais j'ai trouvé une version plus optimisée:
delete test
from test
inner join (
select max(id) as lastId, email
from test
group by email
having count(*) > 1) duplic on duplic.email = test.email
where test.id < duplic.lastId;
Vous pouvez voir que cela supprime les doublons les plus anciens, à savoir 1, 7, 2, 6:
select * from test;
+----+-------+
| id | email |
+----+-------+
| 3 | ccc |
| 4 | bbb |
| 5 | ddd |
| 8 | aaa |
| 9 | eee |
+----+-------+
Une autre version, la suppression proposée par Rene Limon
delete from test
where id not in (
select max(id)
from test
group by email)
Manière correcte est
DELETE FROM `tablename`
WHERE id NOT IN (
SELECT * FROM (
SELECT MAX(id) FROM tablename
GROUP BY name
)
)
Essayez cette méthode
DELETE t1 FROM test t1, test t2
WHERE t1.id > t2.id AND t1.email = t2.email
Je dois dire que la version optimisée est un code doux et élégant qui fonctionne à merveille même lorsque la comparaison est effectuée sur une colonne DATETIME. C'est ce que j'ai utilisé dans mon script, dans lequel je cherchais la dernière date de fin de contrat pour chaque identifiant d'employé:
DELETE CurrentContractData
FROM CurrentContractData
INNER JOIN (
SELECT
EmployeeID,
PeriodofPerformanceStartDate,
max(PeriodofPerformanceEndDate) as lastDate,
ContractID
FROM CurrentContractData
GROUP BY EmployeeID
HAVING COUNT(*) > 1) Duplicate on Duplicate.EmployeeID = CurrentContractData.EmployeeID
WHERE CurrentContractData.PeriodofPerformanceEndDate < Duplicate.lastDate;
Merci beaucoup!