MySQL INSERT IF (пользовательские операторы if)
во-первых, вот краткое резюме вопроса:
можно ли запустить INSERT
заявление условно?
Что-то сродни этому:
IF(expression) INSERT...
теперь, я знаю, что я могу сделать это с помощью хранимой процедуры. Мой вопрос: Могу ли я сделать это в своем запросе?
зачем мне это делать?
предположим, что у нас есть следующие 2 таблицы:
products: id, qty_on_hand
orders: id, product_id, qty
теперь, скажем, заказ на 20 кукол Вуду (код продукта 2) войти.
Сначала мы проверяем, достаточно ли количества под рукой:
SELECT IF(
( SELECT SUM(qty) FROM orders WHERE product_id = 2 ) + 20
<=
( SELECT qty_on_hand FROM products WHERE id = 2)
, 'true', 'false');
затем, если он оценивает значение true, мы запускаем INSERT
запрос.
Пока все хорошо.
однако есть проблема с параллелизмом.
Если 2 заказа пришли в точно в то же время, они могли бы оба прочитать количество под рукой, прежде чем любой из них вошел в заказ.
Затем они оба разместят заказ, тем самым превысив qty_on_hand
.
Итак, вернемся к корню вопроса:
Можно ли запустить INSERT
оператор условно, чтобы мы могли объединить оба этих запроса в один?
Я много искал вокруг, и единственный тип условного INSERT
заявление, которое я мог найти, было ON DUPLICATE KEY
, что, очевидно, здесь не применяется.
4 ответов
INSERT INTO TABLE
SELECT value_for_column1, value_for_column2, ...
FROM wherever
WHERE your_special_condition
если строки не возвращаются из select (потому что ваше специальное условие false), вставка не происходит.
используя вашу схему из вопроса (предполагая, что ваш
попробуй:
INSERT INTO orders(product_id, qty)
SELECT 2, 20 FROM products WHERE id = 2 AND qty_on_hand >= 20
если продукт с id
равна и qty_on_hand
больше или равно 20
для данного продукта, то вставка будет происходить со значениями product_id = 2
и qty = 20
. В противном случае вставка не произойдет.
Примечание: если ваши идентификаторы продукта уникальны, вы можете добавить LIMIT
предложение в конце SELECT
заявление.
вы, вероятно, решаете проблему неправильно.
Если вы боитесь, что две операции чтения будут происходить одновременно, и, следовательно, одна будет работать с устаревшими данными, решение заключается в использовать блокировки или транзакции.
пусть запрос сделает это:
- таблица блокировки для чтения
- читать таблицу
- обновление таблицы
- снять блокировку
Не уверен в параллелизме, вам нужно будет прочитать о блокировке в mysql, но это позволит вам быть уверенным, что вы берете только 20 элементов, если 20 элементов доступны:
update products
set qty_on_hand = qty_on_hand - 20
where qty_on_hand >= 20
and id=2
затем вы можете проверить, сколько строк было затронуто. Если никто не пострадал, у вас не было достаточного запаса. Если 1 строка была затронута, вы эффективно потребляли запас.