Come eliminare da più tabelle in MySQL?


116

Sto cercando di eliminare da alcune tabelle contemporaneamente. Ho fatto un po 'di ricerche e sono arrivato a questo

DELETE FROM `pets` p,
            `pets_activities` pa
      WHERE p.`order` > :order
        AND p.`pet_id` = :pet_id
        AND pa.`id` = p.`pet_id`

Tuttavia, ricevo questo errore

Uncaught Database_Exception [1064]: Hai un errore nella sintassi SQL; controlla il manuale che corrisponde alla versione del tuo server MySQL per la sintassi corretta da usare vicino a 'p, pets_activitiespa ...

Non ho mai cancellato una tabella incrociata prima, quindi per ora sono inesperto e bloccato!

Che cosa sto facendo di sbagliato?

Risposte:


204

Usa una JOINnella DELETEdichiarazione.

DELETE p, pa
      FROM pets p
      JOIN pets_activities pa ON pa.id = p.pet_id
     WHERE p.order > :order
       AND p.pet_id = :pet_id

In alternativa puoi usare ...

DELETE pa
      FROM pets_activities pa
      JOIN pets p ON pa.id = p.pet_id
 WHERE p.order > :order
   AND p.pet_id = :pet_id

... da eliminare solo da pets_activities

Vedi questo .

Per i singoli eliminazioni di tabella, ma con integrità referenziale, ci sono altri modi di fare con EXISTS, NOT EXISTS, IN, NOT INe ecc, ma quello di cui sopra in cui si specifica da cui tavoli da eliminare con un alias prima che la FROMclausola può farti uscire di pochi piuttosto stretto macchie più facilmente. Tendo a raggiungere il EXISTS99% dei casi e poi c'è l'1% in cui questa sintassi MySQL prende la giornata.


7
Ho provato questo "elimina tutto in 1 query" con l'unione di 6 tabelle di grandi dimensioni (ognuno di circa 15.000 righe) e la query ha impiegato 155 secondi per eliminare 63 righe in 6 tabelle: O
Klemen Tušar

1
@cadman Questa è la vera risposta giusta; ci possono essere argomenti contro il suo utilizzo, ma a volte è molto utile
Simon Christian

1
+1 Sono d'accordo che questa sia la vera risposta giusta, dal momento che la domanda non era "dovresti" ma "come fare". Tuttavia, sarei interessato a conoscere l'1% perché non riesco a pensare a una singola situazione in cui sarebbe preferibile.
Erick Robertson

2
@techouse, ti sei iscritto e hai filtrato gli indici? 15k x 15k x 15k x 15k 15k x 15k è 11 milioni. Ci è SELECTvoluto altrettanto tempo?
Paul Draper

6
Puoi anche usare LEFT JOIN, che è utile se la seconda tabella non aveva voci corrispondenti, altrimenti non verrà cancellato nulla.
Lexib il

20

Poiché questa sembra essere una semplice relazione genitore / figlio tra petse pets_activities, faresti meglio a creare il tuo vincolo di chiave esterna con una cascata di eliminazione.

In questo modo, quando una petsriga viene eliminata, pets_activitiesvengono eliminate automaticamente anche le righe ad essa associate.

Quindi la tua query diventa semplice:

delete from `pets`
    where `order` > :order
      and `pet_id` = :pet_id

3
@Erick, a condizione che tu abbia impostato l'integrità referenziale, le eliminazioni a cascata non possono causare più problemi che eliminare da sole. Sappiamo già che paè un figlio adatto a pcausa della id/pet_idmappatura.
paxdiablo

14
Bene, ragazzi avete i vostri pensieri, ma sembra che stiate scontando molto della potenza del DBMS. Le eliminazioni a cascata fanno parte della gestione dei dati tanto quanto trigger, stored procedure o vincoli e sono pericolose solo se non sai cosa stai facendo. Tuttavia, non discuterò ulteriormente il punto, dovremo solo accettare di non essere d'accordo.
paxdiablo

8
Erick, ora hai stuzzicato il mio interesse. Come si garantisce l'integrità dei dati all'interno del database senza vincoli?
paxdiablo

4
@Erick ha detto: "Inoltre, non utilizzo trigger, stored procedure o vincoli". Ah, usi Excel. :-)
james.garriss

4
Voglio solo dare seguito a questo. Ho cambiato la mia posizione sull'eliminazione delle cascate in questa situazione. Ho fatto parte di un nuovo ambiente SQL che li ha usati, li ha usati bene ed erano molto organizzati. In questo sistema ha funzionato molto bene a nostro vantaggio avere queste cascate in atto. Certamente ha impedito i dati orfani e non era pericoloso. Il problema è che tutti coloro che lavorano con il database devono capire come usarli in sicurezza. Ma ci sono sempre dei rischi quando gli sviluppatori junior apportano modifiche al database senza supervisione.
Erick Robertson

14

Usa questo

DELETE FROM `articles`, `comments` 
USING `articles`,`comments` 
WHERE `comments`.`article_id` = `articles`.`id` AND `articles`.`id` = 4

o

DELETE `articles`, `comments` 
FROM `articles`, `comments` 
WHERE `comments`.`article_id` = `articles`.`id` AND `articles`.`id` = 4

1
Ho trovato un buon riferimento per l'utilizzo di questa e alcune altre opzioni su mysqltutorial.org/mysql-delete-statement.aspx
Mavelo

3

Non ho un database mysql su cui testare al momento, ma hai provato a specificare cosa eliminare prima della clausola from? Per esempio:

DELETE p, pa FROM `pets` p,
        `pets_activities` pa
  WHERE p.`order` > :order
    AND p.`pet_id` = :pet_id
    AND pa.`id` = p.`pet_id`

Penso che la sintassi che hai usato sia limitata alle versioni più recenti di mysql.


1
Quella query è stata eseguita con successo, tuttavia, non ha cancellato nessuna riga (ma credo che dovrebbe averlo fatto).
alex

2

La sintassi mi sembra giusta ... prova a cambiarla per usarla INNER JOIN...

Dai un'occhiata a questo .


7
Peccato che tu non abbia incluso la soluzione effettiva, perché il collegamento è corretto!
mycroes

1

Per chiunque abbia letto questo nel 2017, è così che ho fatto qualcosa di simile.

DELETE pets, pets_activities FROM pets inner join pets_activities
on pets_activities.id = pets.id WHERE pets.`order` > :order AND 
pets.`pet_id` = :pet_id

Generalmente, per eliminare righe da più tabelle, la sintassi che seguo è fornita di seguito. La soluzione si basa sul presupposto che esista una relazione tra le due tabelle.

DELETE table1, table2 FROM table1 inner join table2 on table2.id = table1.id
WHERE [conditions]

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.