MySQL підтримує багатотабличні UPDATE і DELETE з JOIN:
-- позначити замовлення заблокованих користувачів
UPDATE orders o
JOIN users u ON u.id = o.user_id
SET o.status = 'cancelled'
WHERE u.is_banned = 1 AND o.status = 'pending';
-- видалити товари з кошиків, яких більше немає в продажу
DELETE ci
FROM cart_items ci
JOIN products p ON p.id = ci.product_id
WHERE p.is_active = 0;
У DELETE перед FROM вказують, з якої таблиці видаляти (DELETE ci), - інакше можна видалити з обох.
Синтаксис відрізняється між СУБД:
-- PostgreSQL
UPDATE orders o SET status = 'cancelled'
FROM users u
WHERE u.id = o.user_id AND u.is_banned;
DELETE FROM cart_items ci USING products p
WHERE p.id = ci.product_id AND NOT p.is_active;
Переносимий варіант - підзапит: WHERE user_id IN (SELECT id FROM users WHERE is_banned = 1).
Обмеження MySQL: не можна змінювати таблицю й одночасно читати з неї в підзапиті:
DELETE FROM orders WHERE id IN (SELECT id FROM orders WHERE ...);
-- ERROR 1093: You can't specify target table 'orders' for update in FROM clause
Обхід - обгорнути підзапит у ще одну похідну таблицю (MySQL матеріалізує її) або переписати через JOIN.
Обережно з масовими змінами:
- Спершу виконати той самий запит як
SELECTі перевірити кількість рядків. - Великі оновлення - порціями з
LIMIT(у багатотабличнихUPDATE/DELETELIMITне дозволений - порції роблять за діапазонамиid). - Блокування:
UPDATE ... JOINблокує рядки, які читає, і в об'єднаній таблиці теж - під навантаженням можливі очікування й deadlock'и.
У Laravel: DB::table('orders')->join('users', ...)->where(...)->update([...]) генерує багатотабличний UPDATE для MySQL.