MySQL, aggiorna più tabelle con una query


132

Ho una funzione che aggiorna tre tabelle, ma per eseguire questa operazione utilizzo tre query. Vorrei utilizzare un approccio più conveniente per le buone pratiche.

Come posso aggiornare più tabelle in MySQL con una singola query?


3
puoi fornire un esempio del codice generato? C'è una chiave comune tra le tabelle?
Jonathan Day

Risposte:


451

Prendi il caso di due tavoli Bookse Orders. Nel caso, aumentiamo il numero di libri in un ordine particolare con Order.ID = 1002in Orderstabella, quindi dobbiamo anche ridurre il numero totale di libri disponibili nel nostro magazzino dello stesso numero nella Bookstabella.

UPDATE Books, Orders
SET Orders.Quantity = Orders.Quantity + 2,
    Books.InStock = Books.InStock - 2
WHERE
    Books.BookID = Orders.BookID
    AND Orders.OrderID = 1002;

Se voglio includere "LIMIT" nella query SQL, devo dire LIMIT 1 o LIMIT 2?
Bluedayz,

2
Qual è il vantaggio di fare questo rispetto a una transazione? Grazie!
paulkon,

2
@paulkon, presumo che quando si utilizzano le transazioni, ci sono molte spese generali in quanto i rollback devono essere disponibili se una qualsiasi procedura nella transazione fallisce.
Thijs Riezebeek,

27
Avviso generale quando si utilizza questa query. La clausola WHERE viene valutata separatamente per ogni tabella. Books.BookID = Orders.BookID è molto importante, senza di esso L'aggiornamento della tabella Books verrebbe eseguito su tutte le righe e non solo per la riga con l'id specificato. Alcune lezioni vengono apprese nel modo più duro, questa è stata appresa nel modo terrificante.
nheimann1,

1
@ nheimann1 Ed è esattamente per questo che consiglio sempre alle persone di usare la sintassi ANSI "inner join". È troppo facile dimenticare quella condizione e ottenere invece un'adesione cartesiana completa.
fool4jesus,

77
UPDATE t1
INNER JOIN t2 ON t2.t1_id = t1.id
INNER JOIN t3 ON t2.t3_id = t3.id
SET t1.a = 'something',
    t2.b = 42,
    t3.c = t2.c
WHERE t1.a = 'blah';

Per vedere cosa aggiornerà, puoi convertirlo in un'istruzione select, ad esempio:

SELECT t2.t1_id, t2.t3_id, t1.a, t2.b, t2.c AS t2_c, t3.c AS t3_c
FROM t1
INNER JOIN t2 ON t2.t1_id = t1.id
INNER JOIN t3 ON t2.t3_id = t3.id
WHERE t1.a = 'blah';

Un esempio che utilizza le stesse tabelle dell'altra risposta:

SELECT Books.BookID, Orders.OrderID,
    Orders.Quantity AS CurrentQuantity,
    Orders.Quantity + 2 AS NewQuantity,
    Books.InStock AS CurrentStock,
    Books.InStock - 2 AS NewStock
FROM Books
INNER JOIN Orders ON Books.BookID = Orders.BookID
WHERE Orders.OrderID = 1002;

UPDATE Books
INNER JOIN Orders ON Books.BookID = Orders.BookID
SET Orders.Quantity = Orders.Quantity + 2,
    Books.InStock = Books.InStock - 2
WHERE Orders.OrderID = 1002;

MODIFICARE:

Solo per divertimento, aggiungiamo qualcosa di un po 'più interessante.

Supponiamo che tu abbia una tabella bookse una tabella di authors. Hai booksun author_id. Ma quando il database è stato originariamente creato, non sono stati impostati vincoli di chiave esterna e successivamente un bug nel codice front-end ha causato l'aggiunta di alcuni libri con messaggi non validi author_id. Come DBA non devi passare attraverso tutti questi booksper verificare quali author_iddovrebbero essere, quindi viene presa la decisione che i catturatori di dati correggeranno il bookspunto a destra authors. Ma ci sono troppi libri per esaminarli e diciamo che sai che quelli che hanno unaauthor_id corrispondente a un reale authorsono corretti. Sono solo quelli che hanno inesistenteauthor_idche non sono validi. Esiste già un'interfaccia per gli utenti per aggiornare i dettagli del libro e gli sviluppatori non vogliono modificarlo solo per questo problema. Ma l'interfaccia esistente fa un INNER JOIN authors, quindi tutti i libri con autori non validi sono esclusi.

Quello che puoi fare è questo: inserisci un record di autore falso come "Autore sconosciuto". Quindi aggiorna author_idtutti i record errati per puntare all'autore sconosciuto. Quindi i catturatori di dati possono cercare tutti i libri con l'autore impostato su "Autore sconosciuto", cercare l'autore corretto e correggerli.

Come si aggiornano tutti i record errati per puntare all'autore sconosciuto? In questo modo (supponendo che l'autore sconosciuto author_idsia 99999):

UPDATE books
LEFT OUTER JOIN authors ON books.author_id = authors.id
SET books.author_id = 99999
WHERE authors.id IS NULL;

Quanto sopra aggiornerà anche booksquello che ha un NULL author_idautore sconosciuto. Se non lo desideri, ovviamente puoi aggiungere AND books.author_id IS NOT NULL.


35

Puoi anche farlo anche con una query usando un join in questo modo:

UPDATE table1,table2 SET table1.col=a,table2.col2=b
WHERE items.id=month.id;

E poi basta inviare questa query, ovviamente. Puoi leggere di più sui join qui: http://dev.mysql.com/doc/refman/5.0/en/join.html . Ci sono anche un paio di restrizioni per ordinare e limitare gli aggiornamenti di più tabelle che puoi leggere qui: http://dev.mysql.com/doc/refman/5.0/en/update.html (basta ctrl + f "join").


È un po 'generoso chiamarlo "join" ;-)
underscore_d

2

Di solito è a questo che servono le stored procedure: implementare diverse istruzioni SQL in una sequenza. Utilizzando i rollback, è possibile assicurarsi che vengano trattati come un'unità di lavoro, ovvero che vengano eseguiti tutti o nessuno di essi, per mantenere coerenti i dati.


dove scriverei la procedura? potresti per favore fornire un esempio?
Adamski,

1
Votato per aver spiegato la necessità dell'atomicità: è anche importante rendersi conto che l'utilizzo di stored procedure non garantisce da solo la coerenza, ma è comunque necessario utilizzare le transazioni; allo stesso modo, le transazioni possono essere eseguite senza utilizzare una procedura memorizzata, a condizione che vengano eseguite sulla stessa connessione. In questo caso, l'uso di un aggiornamento multi-tabella è ancora migliore.
Duncan,

2

Quando dici più query intendi più istruzioni SQL come in:

UPDATE table1 SET a=b WHERE c;
UPDATE table2 SET a=b WHERE d;
UPDATE table3 SET a=b WHERE e;

O più chiamate di funzione di query come in:

mySqlQuery(UPDATE table1 SET a=b WHERE c;)
mySqlQuery(UPDATE table2 SET a=b WHERE d;)
mySqlQuery(UPDATE table3 SET a=b WHERE e;)

Il primo può essere fatto usando una singola chiamata mySqlQuery se è quello che volevi ottenere, semplicemente chiama la funzione mySqlQuery nel modo seguente:

mySqlQuery(UPDATE table1 SET a=b WHERE c; UPDATE table2 SET a=b WHERE d; UPDATE table3 SET a=b WHERE e;)

Ciò eseguirà tutte e tre le query con una chiamata mySqlQuery ().


mySqlQuery () è una funzione personalizzata o incorporata? Voglio saperne di più su questo.
Debashis,

3
Non vi è alcuna differenza significativa tra l'invio di tre query singolarmente o come query multipla, tranne forse se la funzione di query apre una nuova connessione ogni volta. Dal punto di vista dell'esecuzione sul lato server, è la stessa cosa
Duncan il
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.