MySQL, zaktualizuj wiele tabel za pomocą jednego zapytania

138

Mam funkcję, która aktualizuje trzy tabele, ale używam do tego trzech zapytań. Chciałbym zastosować wygodniejsze podejście do dobrych praktyk.

Jak mogę zaktualizować wiele tabel w MySQL za pomocą jednego zapytania?

Adamskiego
źródło
3
czy możesz podać przykład wygenerowanego kodu? Czy istnieje wspólny klucz między tabelami?
Jonathan Day

Odpowiedzi:

459

Weźmy przypadek dwóch tabel Booksi Orders. W przypadku, gdy zwiększamy liczbę książek w określonej kolejności Order.ID = 1002w Orderstabeli, musimy również zmniejszyć tę całkowitą liczbę książek dostępnych w naszym magazynie o tę samą liczbę w Bookstabeli.

UPDATE Books, Orders
SET Orders.Quantity = Orders.Quantity + 2,
    Books.InStock = Books.InStock - 2
WHERE
    Books.BookID = Orders.BookID
    AND Orders.OrderID = 1002;
Irfan
źródło
Jeśli chcę dołączyć „LIMIT” do zapytania SQL, czy muszę powiedzieć LIMIT 1 czy LIMIT 2?
Bluedayz,
2
Jaka jest korzyść z tego w porównaniu z transakcją? Dzięki!
paulkon
2
@paulkon, zakładam, że przy korzystaniu z transakcji wiąże się to z dużym narzutem, ponieważ wycofania muszą być dostępne, jeśli jakakolwiek procedura w transakcji się nie powiedzie.
Thijs Riezebeek
30
Ogólne ostrzeżenie podczas korzystania z tego zapytania. Klauzula WHERE jest oceniana oddzielnie dla każdej tabeli. Books.BookID = Orders.BookID jest bardzo ważne, bez niego Aktualizacja tabeli Books dotknęłaby wszystkich wierszy, a nie tylko wiersza o określonym identyfikatorze. Niektórych lekcji nauczyliśmy się na własnej skórze, tej w przerażający sposób.
nheimann1
2
@ nheimann1 I właśnie dlatego zawsze zalecam ludziom używanie składni ANSI "sprzężenia wewnętrznego". Zbyt łatwo jest zapomnieć o tym stanie i zamiast tego uzyskać pełne sprzężenie kartezjańskie.
fool4jesus
79
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';

Aby zobaczyć, co to ma zamiar zaktualizować, możesz przekonwertować to na instrukcję wyboru, np .:

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';

Przykład wykorzystujący te same tabele co w drugiej odpowiedzi:

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;

EDYTOWAĆ:

Dla zabawy dodajmy coś bardziej interesującego.

Powiedzmy, że masz tabelę booksi tabelę authors. Twój booksmieć author_id. Ale kiedy baza danych została pierwotnie utworzona, nie ustawiono żadnych ograniczeń klucza obcego, a później błąd w kodzie interfejsu użytkownika spowodował, że niektóre książki zostały dodane z nieprawidłowymi author_ids. Jako administrator danych nie chcesz przechodzić przez wszystkie te elementy, booksaby sprawdzić, co author_idpowinno być, więc zostaje podjęta decyzja, że ​​osoby przechwytujące dane naprawią bookspunkt po prawej stronie authors. Ale jest zbyt wiele książek, aby przejść przez każdą z nich i powiedzmy, że wiesz, że te, które mają author_idodpowiednik rzeczywistego, authorsą poprawne. To tylko te, których nie maauthor_ids, które są nieprawidłowe. Istnieje już interfejs umożliwiający użytkownikom aktualizację szczegółów książki, a programiści nie chcą tego zmieniać tylko z powodu tego problemu. Ale istniejący interfejs ma INNER JOIN authors, więc wszystkie książki z nieprawidłowymi autorami są wykluczone.

Możesz to zrobić: wstaw fałszywy wpis autora, np. „Nieznany autor”. Następnie zaktualizuj author_idwszystkie złe rekordy, aby wskazywały na nieznanego autora. Następnie osoby przechwytujące dane mogą wyszukiwać wszystkie książki z autorem ustawionym na „Nieznany autor”, wyszukiwać właściwego autora i poprawiać go.

Jak zaktualizować wszystkie złe rekordy, aby wskazywały na nieznanego autora? W ten sposób (zakładając, że autor nieznany author_idto 99999):

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

Powyższe zaktualizuje również, booksktóre mają NULL author_idnieznanego autora. Jeśli tego nie chcesz, możesz oczywiście dodać AND books.author_id IS NOT NULL.

Wodin
źródło
35

Możesz to również zrobić za pomocą jednego zapytania, używając takiego sprzężenia:

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

A potem oczywiście wyślij to jedno zapytanie. Możesz przeczytać więcej o połączeniach tutaj: http://dev.mysql.com/doc/refman/5.0/en/join.html . Istnieje również kilka ograniczeń dotyczących zamawiania i ograniczania wielu aktualizacji tabel, o których możesz przeczytać tutaj: http://dev.mysql.com/doc/refman/5.0/en/update.html (po prostu ctrl + f "join").

Stephen Searles
źródło
1
Trochę hojnie jest nazywać to „dołączeniem” ;-)
podkreślenie_d
3

Kiedy mówisz wiele zapytań, masz na myśli wiele instrukcji SQL, jak w:

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

Lub wiele wywołań funkcji zapytań, jak w:

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

To pierwsze można zrobić za pomocą pojedynczego wywołania mySqlQuery, jeśli to właśnie chciałeś osiągnąć, po prostu wywołaj funkcję mySqlQuery w następujący sposób:

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

Spowoduje to wykonanie wszystkich trzech zapytań za pomocą jednego wywołania mySqlQuery ().

code_burgar
źródło
mySqlQuery () jest funkcją niestandardową czy wbudowaną? Chcę wiedzieć więcej na ten temat.
Debashis
3
Nie ma znaczącej różnicy między wysyłaniem trzech zapytań pojedynczo lub w postaci wielu zapytań, z wyjątkiem być może sytuacji, gdy funkcja zapytania za każdym razem otwiera nowe połączenie. Z punktu widzenia wykonywania po stronie serwera jest to samo
Duncan
2

Zwykle do tego służą procedury składowane: do zaimplementowania kilku instrukcji SQL w sekwencji. Korzystając z wycofywania zmian, możesz zapewnić, że są one traktowane jako jedna jednostka pracy, tj. Albo wszystkie są wykonywane, albo żadna z nich nie jest, aby zachować spójność danych.

SteveCav
źródło
gdzie napisałbym procedurę? czy mógłbyś podać przykład?
Adamski
1
Głosowano za wyjaśnieniem konieczności atomowości - ważne jest również, aby zdać sobie sprawę, że korzystanie z procedur składowanych nie tylko gwarantuje spójność, nadal trzeba korzystać z transakcji; podobnie transakcje można wykonywać bez użycia procedury składowanej, pod warunkiem, że są wykonywane w tym samym połączeniu. W takim przypadku użycie aktualizacji wielostolikowej jest jeszcze lepsze.
Duncan
0

Powiedzmy, że mam Table1z kluczem podstawowym _idi kolumną logiczną doc_availability; Table2z kluczem obcym _idi kolumną DateTime last_updatei chcę zmienić dostępność dokumentu z _id14 Table1na 0, tj. niedostępny i zaktualizować Table2datownikiem, kiedy dokument był ostatnio aktualizowany. Następujące zapytanie wykonałoby zadanie:

UPDATE Table1, Table2 
SET doc_availability = 0, last_update = NOW() 
WHERE Table1._id = Table2._id AND Table1._id = 14
Clement B. Oke
źródło