MySQL INSERT IF (пользовательские операторы if) - PullRequest
31 голосов
/ 28 июля 2011

Во-первых, вот краткое резюме вопроса:

Можно ли условно выполнить оператор 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.Пока все хорошо.


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


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

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

Ответы [ 4 ]

50 голосов
/ 28 июля 2011
INSERT INTO TABLE
SELECT value_for_column1, value_for_column2, ...
FROM wherever
WHERE your_special_condition

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

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

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

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

Хорошая идея, кстати!

17 голосов
/ 28 июля 2011

Попробуйте:

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.

2 голосов
/ 28 июля 2011

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

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

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

1 голос
/ 28 июля 2011

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

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

* 1006.* Пусть запрос сделает это:
  • таблица блокировок для чтения
  • таблица чтения
  • таблица обновлений
  • разблокировка блокировки
...