Come eliminare dalla selezione in MySQL?


86

Questo codice non funziona per MySQL 5.0, come riscriverlo per farlo funzionare

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

Voglio eliminare le colonne che non hanno un ID univoco. Aggiungerò che la maggior parte delle volte è solo un id (ho provato la sintassi in e non funziona neanche).

Risposte:


212

SELECT(sotto) query restituiscono set di risultati . Quindi devi usare IN, non =nella tua WHEREclausola.

Inoltre, come mostrato in questa risposta, non è possibile modificare la stessa tabella da una sottoquery all'interno della stessa query. Tuttavia, puoi SELECTquindi DELETEin query separate o nidificare un'altra sottoquery e alias il risultato della sottoquery interna (sembra piuttosto hacky, però):

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

Oppure usa i join come suggerito da Mchl .


1
Avevo un tavolo con 150 chiavi duplicate. Ho eseguito la query sopra e ha detto "144 righe interessate", ma c'erano ancora chiavi duplicate. Quindi ho eseguito di nuovo la query e dice che 5 righe interessate, di nuovo: 1 riga interessata. Quindi tutte le chiavi duplicate sono finite. Perchè è questo?
Alex

Questo sta accadendo, perché stai eliminando solo 1 voce da ogni serie di duplicati:SELECT id FROM posts GROUP BY id HAVING ( COUNT(id) > 1 )
havvg

# 1248 - Ogni tabella derivata deve avere il proprio alias
thang

@thang: ecco perché ho detto di alias la sottoquery interna.
BoltClock

1
Puoi spiegare per favore cosa fa "As p"?
Giocatore di cricket

22
DELETE 
  p1
  FROM posts AS p1 
CROSS JOIN (
  SELECT ID FROM posts GROUP BY id HAVING COUNT(id) > 1
) AS p2
USING (id)

Sembra funzionare, ma sono confuso dalla sintassi e non riesco a trovare risorse altrove per spiegarlo. CROSS JOINapparentemente esegue un join cartesiano, quindi sembra che questo potrebbe fare un lavoro non necessario o eseguire in modo subottimale? Qualcuno potrebbe spiegare?
wintron

Farà un prodotto cartesiano solo se non ci sono USINGclausole. Con USINGil prodotto è limitato a coppie aventi lo stesso valore in idcolonna, quindi è in effetti molto limitato.
Mchl

Potresti fare la stessa cosa con inner join? 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: Sì. Funzionalmente queste giunzioni sono esattamente le stesse.
Mchl

5

puoi usare inner join:

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  

0

Se desideri eliminare tutti i duplicati, ma uno su ciascun set di duplicati, questa è una soluzione:

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;
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.