MySQL, оновіть кілька таблиць одним запитом


132

У мене є функція, яка оновлює три таблиці, але для цього я використовую три запити. Я хочу використовувати більш зручний підхід для належної практики.

Як я можу оновити кілька таблиць у MySQL за допомогою одного запиту?


3
чи можете ви навести приклад згенерованого коду? Чи є загальний ключ між таблицями?
День Джонатана

Відповіді:


451

Візьміть випадок двох таблиць Booksі Orders. У разі, якщо ми збільшуємо кількість книг в певному порядку з Order.ID = 1002в Ordersтаблиці , то ми повинні також скоротити , що загальне число книг , доступних на нашому складі по тим же номером в Booksтаблиці.

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

Якщо я хочу включити "LIMIT" до SQL-запиту, чи потрібно сказати LIMIT 1 або LIMIT 2?
Bluedayz

2
Яка перевага робити це проти транзакції? Дякую!
paulkon

2
@paulkon, я припускаю, що при використанні транзакцій виникає багато накладних витрат, оскільки відкат повинен бути доступний, якщо будь-яка процедура транзакції завершилася невдачею.
Thijs Riezebeek

27
Загальне попередження при використанні цього запиту. Запит WHERE оцінюється окремо для кожної таблиці. Books.BookID = Orders.BookID дуже важливий, без нього оновлення таблиці Books відбудеться для всіх рядків, а не лише для рядка із вказаним ідентифікатором. Деякі уроки засвоюються важким способом, цього засвоїли жахливим чином.
nheimann1

1
@ nheimann1 І саме тому я завжди рекомендую людям використовувати синтаксис ANSI "внутрішнє з'єднання". Забути цю умову занадто просто і натомість отримати повну декартову приєднання.
crazy4jesus

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

Щоб побачити, що це буде оновлено, ви можете перетворити це у вибраний оператор, наприклад:

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

Приклад, що використовує ті ж таблиці, що й інша відповідь:

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;

Редагувати:

Просто для розваги додамо щось трохи цікавіше.

Скажімо, у вас є таблиця booksта таблиця authors. У вас booksє author_id. Але коли база даних була створена спочатку, жодних обмежень щодо зовнішніх ключів не було встановлено, а пізніше помилка в коді передумови викликала додавання деяких книг з недійсними author_ids. Як DBA, вам не потрібно проходити все це, booksщоб перевірити, що author_idмає бути, тому приймається рішення, що фіксатори даних будуть фіксувати booksточку вправо authors. Але є занадто багато книг, щоб пройти кожну з них, і скажемо, що ви знаєте, що ті, у яких є author_idвідповідність дійсним, authorє правильними. Це просто ті, які не існуютьauthor_ids, які є недійсними. Вже є інтерфейс для користувачів, щоб оновити реквізити книги, і розробники не хочуть змінювати це лише для цієї проблеми. Але існуючий інтерфейс робить INNER JOIN authors, тому всі книги з недійсними авторами виключені.

Що ви можете зробити, це: вставити підроблений авторський запис на зразок "Невідомий автор". Потім оновіть author_idвсі погані записи, щоб вказати на Невідомого автора. Тоді фіксатори даних можуть шукати всі книги з автором, встановленим на "Невідомий автор", шукати правильного автора та виправляти їх.

Як ви оновлюєте всі погані записи, щоб вказати на Невідомого автора? Ось так (припускаючи, що Невідомий автор author_id99999):

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

Викладене вище також буде оновлено, booksякі мають NULL author_idневідомого автора. Якщо ви цього не хочете, звичайно, можете додати AND books.author_id IS NOT NULL.


35

Ви також можете зробити це за допомогою одного запиту, використовуючи приєднання на зразок:

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

А потім просто надішліть цей запит, звичайно. Детальніше про приєднання ви можете прочитати тут: http://dev.mysql.com/doc/refman/5.0/uk/join.html . Також є кілька обмежень для замовлення та обмеження кількох оновлень таблиці, про які ви можете прочитати тут: http://dev.mysql.com/doc/refman/5.0/en/update.html (просто ctrl + f "приєднатися").


Трохи великодушно називати "приєднання" ;-)
підкреслюй

2

Ось зазвичай для цього зберігаються процедури: реалізувати кілька операторів SQL в послідовності. Використовуючи зворотні звороти, ви можете переконатися, що вони розглядаються як одна одиниця роботи, тобто або всі вони виконуються, або жодна з них не забезпечує збереження даних.


де я б писав процедуру? Ви можете надати приклад?
Адамські

1
Оголошений за пояснення необхідності атомності - важливо також усвідомити, що використання збережених процедур не є одним лише гарантією послідовності, вам все одно потрібно використовувати транзакції; так само транзакції можуть здійснюватися без використання збереженої процедури, за умови, що вони здійснюються через одне і те ж з'єднання. У цьому випадку використання оновлення з кількома таблицями ще краще.
Дункан

2

Коли ви говорите кілька запитів, ви маєте на увазі кілька операторів SQL, як у:

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

Або кілька запитів функцій запитів, як у:

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

Перше все можна зробити за допомогою одного виклику mySqlQuery, якщо саме цього ви хотіли досягти, просто зателефонуйте до функції mySqlQuery таким чином:

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

Це виконає всі три запити одним викликом mySqlQuery ().


mySqlQuery () - це власна функція або вбудована функція? Я хочу знати більше про це.
Дебашис

3
Немає суттєвої різниці між надсиланням трьох запитів окремо або як декілька запитів, за винятком, можливо, якщо ваша функція запиту щоразу відкриває нове з'єднання. З точки зору виконання серверного боку, це те саме
Данкан
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.