Elimina con Join in MySQL


501

Ecco lo script per creare le mie tabelle:

CREATE TABLE clients (
   client_i INT(11),
   PRIMARY KEY (client_id)
);
CREATE TABLE projects (
   project_id INT(11) UNSIGNED,
   client_id INT(11) UNSIGNED,
   PRIMARY KEY (project_id)
);
CREATE TABLE posts (
   post_id INT(11) UNSIGNED,
   project_id INT(11) UNSIGNED,
   PRIMARY KEY (post_id)
);

Nel mio codice PHP, quando elimino un client, voglio eliminare tutti i post dei progetti:

DELETE 
FROM posts
INNER JOIN projects ON projects.project_id = posts.project_id
WHERE projects.client_id = :client_id;

La tabella di messaggi non dispone di una chiave esterna client_id, solo project_id. Voglio eliminare i post nei progetti che hanno superato client_id.

Al momento non funziona perché non vengono eliminati post.


10
Penso che la risposta di Yehosef dovrebbe essere quella accettata, dal momento che usa Join come da te richiesto e che funziona meglio dell'uso di una clausola IN come yukondude ha proposto ...
Gerardo Grignoli,

2
Il modello preferito è un DELETE posts FROM posts JOIN projects ..., piuttosto che un IN (subquery)modello. (La risposta di Yehosef fornisce un esempio del modello preferito.)
spencer7593

@GerardoGrignoli, funziona meglio per un particolare motore o versione di MySQL? Non c'è motivo per cui le due query debbano funzionare diversamente, poiché AFAIK sono identiche. Certo, se avessi un nickel ogni volta che il mio ottimizzatore di query faceva qualcosa di stupido ....
Paul Draper

Puoi anche usare aliasil nome della tabella e usarlo.
Biniam,

Risposte:


1254

Devi solo specificare che vuoi eliminare le voci dalla poststabella:

DELETE posts
FROM posts
INNER JOIN projects ON projects.project_id = posts.project_id
WHERE projects.client_id = :client_id

EDIT: per maggiori informazioni puoi vedere questa risposta alternativa


117
Va notato che questa è la risposta corretta perché l'unione ti costringe a utilizzare "ELIMINA i post DA" invece dei normali "ELIMINA post", poiché la tabella da eliminare non è più inequivocabile. Grazie!
siannopollo,

8
Nota che qui non puoi usare il metodo 'as', ad es. Progetti di join interni come p su p.project_id ...
zzapper,

14
In realtà è possibile utilizzare un alias per le tabelle unite, ma non per la tabella principale (post). "ELIMINA post DA post INNER JOIN progetti p ON p.project_id = posts.project_id"
Weboide,


14
questa è la risposta migliore perché puoi anche eliminare da entrambe le tabelle in una sola azioneDELETE posts , projects FROM posts INNER JOIN projects ON projects.project_id = posts.project_id WHERE projects.client_id = :client_id
Developerium,

84

Poiché si selezionano più tabelle, la tabella da eliminare non è più inequivocabile. Devi selezionare :

DELETE posts FROM posts
INNER JOIN projects ON projects.project_id = posts.project_id
WHERE projects.client_id = :client_id

In questo caso, table_name1e table_name2sono la stessa tabella, quindi funzionerà:

DELETE projects FROM posts INNER JOIN [...]

Puoi anche eliminare da entrambe le tabelle se desideri:

DELETE posts, projects FROM posts INNER JOIN [...]

Si noti che order bye limit non funziona per le eliminazioni multi-tavolo .

Si noti inoltre che se si dichiara un alias per una tabella, è necessario utilizzare l'alias quando si fa riferimento alla tabella:

DELETE p FROM posts as p INNER JOIN [...]

Contributi di Carpetsmoker ed ecc .


3
Se stai fornendo una risposta migliore, almeno potresti rendere più leggibile l'SQL. Tutti gli altri riferimenti SQL in questa domanda hanno parole chiave in maiuscolo (tranne uno con 0 voti). Non sono sicuro del motivo per cui hai ripristinato le mie modifiche.
Yehosef,

3
@Yehosef, c'è un gruppo di persone che trova i CAPS davvero abbaglianti. Credo di non essere il solo, ho visto anche un bel po 'di persone diventare minuscole.
Pacerier,

1
abbastanza giusto - Rispetto il tuo diritto di scrivere la tua risposta nello stile che ti piace;)
Yehosef

7
Per aggiungere alla discussione caps / no caps, vero, puoi usare lo stile che preferisci, ma nella tua risposta, stai effettivamente mescolando stili dove ritieni opportuno: ONè in maiuscolo. Agli sviluppatori meno esperti, può significare che è OK essere disordinato e incoerente in termini di stile.
Ombra

16
LE PAROLE CHIAVE DI CAPS non sono abbaglianti. STANNO RIPRENDENDO LE DOMANDE;)
Sachem,

50

O la stessa cosa, con una sintassi leggermente diversa (più amichevole IMO):

DELETE FROM posts 
USING posts, projects 
WHERE projects.project_id = posts.project_id AND projects.client_id = :client_id;

A proposito, con mysql usare i join è quasi sempre molto più veloce delle subquery ...


Cosa significa USING?
CMCDragonkai,


10
@ bigtex777: Nota che la parola chiave USING nelle istruzioni SELECT ha poco a che fare con la stessa parola chiave in un'istruzione DELETE. In SELECTs specifica l'elenco di colonne su cui unire, mentre in DELETEs è un elenco di tutte le tabelle in un join
ivanhoe

42

Puoi anche usare ALIAS in questo modo funziona appena usato sul mio database! È necessario eliminare la tabella!

DELETE t FROM posts t
INNER JOIN projects p ON t.project_id = p.project_id
AND t.client_id = p.client_id

1
questo è utile sui join di tasti composti per evitare di ripetere i nomi delle tabelle
Marquez,

1
"In realtà è possibile utilizzare un alias per le tabelle unite, ma non per la tabella principale (post). 'ELIMINA post DA post INNER JOIN progetti p ON p.project_id = posts.project_id'" - @ Weboide
Jeaf Gilbert,

2
In realtà (citando da dev.mysql.com/doc/refman/5.0/en/delete.html ) "Se si dichiara un alias per una tabella, è necessario utilizzare l'alias quando si fa riferimento alla tabella: DELETE t1 FROM test AS t1, test2 DOVE ... "quindi usare un alias va bene.
Peter Bowers,

25

Sono più abituato alla soluzione di subquery a questo, ma non l'ho provato in MySQL:

DELETE  FROM posts
WHERE   project_id IN (
            SELECT  project_id
            FROM    projects
            WHERE   client_id = :client_id
        );

85
Dovresti davvero evitare di usare la parola chiave IN in SQL (anche se di solito è più facile da capire per i principianti) e utilizzare invece JOIN (quando possibile), poiché le sottoquery di solito rendono le cose molto più lente.
user276648,

14
Ciò tende a causare l'arresto anomalo del DB in presenza di un numero enorme di righe restituite dalla query secondaria. È anche immensamente lento.
Raj

2
@yukondude In effetti "IN" è molto più facile da capire rispetto a "JOIN" al primo, ed è per questo che le persone che non hanno davvero familiarità con SQL finiranno per scrivere "IN" ovunque, mentre potrebbero usare "JOIN" che funziona meglio ( o molto meglio, a seconda della query). Ricordo che diversi anni fa, quasi tutte le mie query SQL sarebbero state riscritte da qualcuno che sapeva davvero scrivere buone query. Ecco perché ho aggiunto il commento per evitare "IN", in modo che le persone sappiano che, se possibile, dovrebbero evitare di usarlo.
user276648,

10
La vera ragione per cui sono arrivato a questa pagina è perché la query che ho scritto con un'istruzione IN era lenta. Evita assolutamente la risposta accettata qui.
MikeKulls,

4
Per quanto vecchia sia questa domanda, è importante sapere PERCHÉ dovresti usare JOIN invece di IN. Quando la condizione in cui la condizione viene eseguita su una riga, verrà eseguita la query all'interno di IN. Ciò significa che se ci sono 100 righe che devono essere verificate rispetto a WHERE, quella subquery verrà eseguita 100 volte. Considerando che un JOIN eseguirà solo UNA VOLTA. Quindi, man mano che il tuo db diventa sempre più grande, quella query impiegherà sempre più tempo per terminare. @markus solo perché qualcosa non è critico non significa che dovresti scrivere un codice errato. Scriverlo un po 'meglio ti farà risparmiare un sacco di tempo e mal di testa in futuro. :)
RisingSun

11

MySQL DELETE registra con JOIN

In genere si utilizza INNER JOIN nell'istruzione SELECT per selezionare i record da una tabella con record corrispondenti in altre tabelle. È inoltre possibile utilizzare la clausola INNER JOIN con l'istruzione DELETE per eliminare i record da una tabella e anche i record corrispondenti in altre tabelle, ad esempio per eliminare i record da entrambe le tabelle T1 e T2 che soddisfano una condizione particolare, utilizzare la seguente istruzione:

DELETE T1, T2
FROM T1
INNER JOIN T2 ON T1.key = T2.key
WHERE condition

Si noti che si inseriscono i nomi di tabella T1 e T2 tra CANC e DA. Se si omette la tabella T1, l'istruzione DELETE elimina solo i record nella tabella T2 e se si omette la tabella T2, vengono eliminati solo i record nella tabella T1.

La condizione di join T1.key = T2.key specifica i record corrispondenti nella tabella T2 che devono essere eliminati.

La condizione nella clausola WHERE specifica quali record nei T1 e T2 che devono essere eliminati.


11

Elimina tabella singola:

Per eliminare le voci dalla poststabella:

DELETE ps 
FROM clients C 
INNER JOIN projects pj ON C.client_id = pj.client_id
INNER JOIN posts ps ON pj.project_id = ps.project_id
WHERE C.client_id = :client_id;

Per eliminare le voci dalla projectstabella:

DELETE pj 
FROM clients C 
INNER JOIN projects pj ON C.client_id = pj.client_id
INNER JOIN posts ps ON pj.project_id = ps.project_id
WHERE C.client_id = :client_id;

Per eliminare le voci dalla clientstabella:

DELETE C
FROM clients C 
INNER JOIN projects pj ON C.client_id = pj.client_id
INNER JOIN posts ps ON pj.project_id = ps.project_id
WHERE C.client_id = :client_id;

Elimina più tabelle:

Per eliminare le voci da più tabelle dai risultati uniti, è necessario specificare i nomi delle tabelle dopo DELETEcome elenco separato da virgole:

Si supponga di voler eliminare le voci da tutte le tre tabelle ( posts, projects, clients) per un cliente particolare:

DELETE C,pj,ps 
FROM clients C 
INNER JOIN projects pj ON C.client_id = pj.client_id
INNER JOIN posts ps ON pj.project_id = ps.project_id
WHERE C.client_id = :client_id

7

Prova come di seguito:

DELETE posts.*,projects.* 
FROM posts
INNER JOIN projects ON projects.project_id = posts.project_id
WHERE projects.client_id = :client_id;

4

Un altro metodo di eliminazione utilizzando una sottoselezione migliore dell'uso INsarebbeWHERE EXISTS

DELETE  FROM posts
WHERE   EXISTS ( SELECT  1 
                 FROM    projects
                 WHERE   projects.client_id = posts.client_id);

Un motivo per usare questo invece del join è che a DELETEwith ne JOINproibisce l'uso LIMIT. Se si desidera eliminare in blocchi in modo da non produrre blocchi di tabella completi, è possibile aggiungere LIMITutilizzare questo DELETE WHERE EXISTSmetodo.


1
Questa query può essere scritta con "alias"? Dalla sintassi non è molto chiaro come postsall'interno di EXISTS () sia lo stesso da postscui vengono eliminate le righe. (IMHO comunque)
MattBianco,

Ti sento, ma gli alias non sono consentiti nella tabella da cui eliminare. I "post" nella query secondaria devono essere il nome completo della tabella, il che significa che se si desidera riutilizzare quella tabella nella clausola Sottoseleziona da, è necessario alias lì.
Jim Clouse,

1
Funziona così:DELETE p FROM posts p WHERE EXISTS ( SELECT 1 FROM projects WHERE projects.client_id = p.client_id);
MattBianco,

4
mysql> INSERT INTO tb1 VALUES(1,1),(2,2),(3,3),(6,60),(7,70),(8,80);

mysql> INSERT INTO tb2 VALUES(1,1),(2,2),(3,3),(4,40),(5,50),(9,90);

ELIMINA record da una tabella:

mysql> DELETE tb1 FROM tb1,tb2 WHERE tb1.id= tb2.id;

ELIMINA RECORD DA entrambe le tabelle:

mysql> DELETE tb2,tb1 FROM tb2 JOIN tb1 USING(id);

1

Se join non funziona per te, puoi provare questa soluzione. Serve per cancellare i record orfani da t1 quando non si usano chiavi esterne + dove specifico condizione. Vale a dire cancella i record da table1, che hanno un campo vuoto "code" e che non hanno record in table2, corrispondenti al campo "name".

delete table1 from table1 t1 
    where  t1.code = '' 
    and 0=(select count(t2.name) from table2 t2 where t2.name=t1.name);

0

Prova questo,

DELETE posts.*
FROM posts
INNER JOIN projects ON projects.project_id = posts.project_id
WHERE projects.client_id = :client_id

-3

- Si noti che non è possibile utilizzare un alias sopra la tabella in cui è necessario eliminare

DELETE tbl_pagos_activos_usuario
FROM tbl_pagos_activos_usuario, tbl_usuarios b, tbl_facturas c
Where tbl_pagos_activos_usuario.usuario=b.cedula
and tbl_pagos_activos_usuario.cod=c.cod
and tbl_pagos_activos_usuario.rif=c.identificador
and tbl_pagos_activos_usuario.usuario=c.pay_for
and tbl_pagos_activos_usuario.nconfppto=c.nconfppto
and NOT ISNULL(tbl_pagos_activos_usuario.nconfppto)
and c.estatus=50
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.