Подтвердить что ты не робот

MySQL INSERT IF (пользовательские операторы if)

Во-первых, здесь краткое изложение вопроса:

Можно ли условно выполнить оператор INSERT? Что-то похожее на это:

IF(expression) INSERT...

Теперь я знаю, что могу сделать это с помощью хранимой процедуры. Мой вопрос: могу ли я сделать это в моем запросе?


Теперь, зачем мне это делать?

Предположим, что у нас есть следующие 2 таблицы:

products: id, qty_on_hand
orders: id, product_id, qty

Теперь, скажем, приказ о 20 куклах Voodoo (номер продукта 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.
Пока все хорошо.


Однако есть проблема с concurrency.
Если в тот же момент приходят 2 заказа, они могут прочитать количество на руках, прежде чем какой-либо из них введет порядок. Затем они будут размещать заказ, превышая qty_on_hand.


Итак, вернемся к корню вопроса:
Можно ли условно выполнить оператор INSERT, чтобы мы могли объединить оба эти запроса в один?

Я искал много, и единственный тип условного оператора INSERT, который я мог найти, был ON DUPLICATE KEY, который, очевидно, здесь не применяется.

4b9b3361

Ответ 1

INSERT INTO TABLE
SELECT value_for_column1, value_for_column2, ...
FROM wherever
WHERE your_special_condition

Если никакие строки не возвращаются из select (поскольку ваше специальное условие ложно), никакая вставка не происходит.

Использование вашей схемы из вопроса (если ваш столбец id auto_increment):

insert into orders (product_id, qty)
select 2, 20
where (SELECT qty_on_hand FROM products WHERE id = 2) > 20;

Это не будет вставлять никакие строки, если на складе недостаточно запасов, иначе он создаст строку порядка.

Хорошая идея btw!

Ответ 2

Try:

INSERT INTO orders(product_id, qty)
SELECT 2, 20 FROM products WHERE id = 2 AND qty_on_hand >= 20

Если существует продукт с id, равным 2, а qty_on_hand больше или равно 20 для этого продукта, тогда вставка будет иметь значения product_id = 2 и qty = 20. В противном случае никакой вставки не будет.

Примечание. Если идентификаторы продуктов уникальны, вы можете добавить предложение LIMIT в конце инструкции SELECT.

Ответ 3

Вероятно, вы решили проблему неправильно.

Если вы боитесь, что одновременно будут выполняться две операции чтения и, следовательно, вы будете работать со устаревшими данными, решение будет использовать блокировки или транзакции.

Попросите выполнить запрос:

  • таблица блокировки для чтения
  • прочитать таблицу
  • таблица обновлений
  • блокировка релиза

Ответ 4

Не уверен в concurrency, вам нужно будет прочитать о блокировке в mysql, но это позволит вам быть уверенным, что вы принимаете только 20 элементов, если доступно 20 элементов:

update products 
set qty_on_hand = qty_on_hand - 20 
where qty_on_hand >= 20
and id=2

Затем вы можете проверить, сколько строк было затронуто. Если ни одна из них не была затронута, у вас не было достаточного запаса. Если затронута 1 строка, вы эффективно воспользовались запасом.