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 строка была затронута, вы эффективно потребляли запас.