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
, который, очевидно, здесь не применяется.
Ответы
Ответ 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 строка, вы эффективно воспользовались запасом.