Comment supprimer de select dans MySQL?

86

Ce code ne fonctionne pas pour MySQL 5.0, comment le réécrire pour le faire fonctionner

DELETE FROM posts where id=(SELECT id FROM posts GROUP BY id  HAVING ( COUNT(id) > 1 ))

Je souhaite supprimer les colonnes qui n'ont pas d'identifiant unique. J'ajouterai que la plupart du temps, c'est un seul identifiant (j'ai essayé la syntaxe et cela ne fonctionne pas aussi).

IAdapter
la source

Réponses:

213

SELECTLes (sous) requêtes renvoient des ensembles de résultats . Vous devez donc utiliser IN, pas =dans votre WHEREclause.

En outre, comme indiqué dans cette réponse, vous ne pouvez pas modifier la même table à partir d'une sous-requête dans la même requête. Cependant, vous pouvez soit SELECTalors DELETEdans des requêtes séparées, soit imbriquer une autre sous-requête et aliaser le résultat de la sous-requête interne (semble plutôt hacky, cependant):

DELETE FROM posts WHERE id IN (
    SELECT * FROM (
        SELECT id FROM posts GROUP BY id HAVING ( COUNT(id) > 1 )
    ) AS p
)

Ou utilisez des jointures comme suggéré par Mchl .

BoltClock
la source
1
J'avais une table avec 150 clés en double. J'ai exécuté la requête ci-dessus et il a dit "144 lignes affectées", mais là où encore des clés en double. J'ai donc exécuté à nouveau la requête et il est indiqué 5 lignes affectées, encore une fois: 1 ligne affectée. Ensuite, toutes les clés en double ont disparu. Pourquoi est-ce?
Alex
Cela se produit, car vous ne supprimez qu'une seule entrée de chaque ensemble de doublons:SELECT id FROM posts GROUP BY id HAVING ( COUNT(id) > 1 )
havvg
# 1248 - Chaque table dérivée doit avoir son propre alias
thang
@thang: C'est pourquoi j'ai dit d'aliaser la sous-requête interne.
BoltClock
1
Pouvez-vous expliquer ce que fait le "As p"?
Cricketer
22
DELETE 
  p1
  FROM posts AS p1 
CROSS JOIN (
  SELECT ID FROM posts GROUP BY id HAVING COUNT(id) > 1
) AS p2
USING (id)
Mchl
la source
Cela semble fonctionner, mais je suis confus par la syntaxe et je ne trouve aucune ressource ailleurs pour l'expliquer. CROSS JOINeffectue apparemment une jointure cartésienne, il semble donc que cela puisse faire un travail inutile ou fonctionner de manière sous-optimale? Quelqu'un pourrait-il expliquer?
wintron
Il ne fera un produit cartésien que s'il n'y a pas de USINGclause. Le USINGproduit étant limité aux paires ayant la même valeur en idcolonne, il est donc en fait très limité.
Mchl
Pourriez-vous faire la même chose avec la jointure intérieure? IEDELETE p1 FROM posts AS p1 INNER JOIN ( SELECT ID FROM posts GROUP BY id HAVING COUNT(id) > 1 ) AS p2 ON p2.ID=p1.ID
Kodos Johnson
1
@Andrew: Oui. Fonctionnellement, ces jointures sont exactement les mêmes.
Mchl
5

vous pouvez utiliser la jointure interne:

DELETE 
    ps 
FROM 
    posts ps INNER JOIN 
         (SELECT 
           distinct id 
         FROM 
             posts 
         GROUP BY id  
      HAVING COUNT(id) > 1 ) dubids on dubids.id = ps.id  
Charif DZ
la source
0

Si vous souhaitez supprimer tous les doublons, mais un sur chaque ensemble de doublons, voici une solution:

DELETE posts
FROM posts
LEFT JOIN (
    SELECT id
    FROM posts
    GROUP BY id
    HAVING COUNT(id) = 1

    UNION

    SELECT id
    FROM posts
    GROUP BY id
    HAVING COUNT(id) != 1
) AS duplicate USING (id)
WHERE duplicate.id IS NULL;
havvg
la source