MySQL INSERT IF (custom if statements)
tout d'abord, voici le résumé concis de la question:
est-il possible de lancer un INSERT
instruction conditionnelle?
Quelque chose qui ressemble à ceci:
IF(expression) INSERT...
Maintenant, je sais que je peux le faire avec une procédure stockée. Ma question est: puis-je faire dans ma requête?
Maintenant, pourquoi voudrais-je faire?
supposons que nous ayons les 2 tableaux suivants:
products: id, qty_on_hand
orders: id, product_id, qty
maintenant, disons une commande pour 20 Poupées Voodoo (produit id 2) arrive.
Nous vérifions d'abord si il y a assez de Quantité:
SELECT IF(
( SELECT SUM(qty) FROM orders WHERE product_id = 2 ) + 20
<=
( SELECT qty_on_hand FROM products WHERE id = 2)
, 'true', 'false');
Ensuite, si elle est true, l' INSERT
requête.
So far So good.
Cependant, il y a un problème avec la concurrence.
Si 2 ordres arrivent à la exact même temps, il se peut qu'ils lisent tous les deux la quantité en main avant que l'un d'eux n'entre dans la commande.
Ils passeront alors tous les deux la commande, donc le dépassement de la qty_on_hand
.
Donc, revenons à la racine de la question:
Est-il possible de lancer un INSERT
déclaration conditionnellement, de sorte que nous puissions combiner ces deux requêtes en une seule?
j'ai cherché autour d'un lot, et le seul type de conditionnel INSERT
déclaration que j'ai pu trouver était ON DUPLICATE KEY
, ce qui ne s'applique évidemment pas ici.
4 réponses
INSERT INTO TABLE
SELECT value_for_column1, value_for_column2, ...
FROM wherever
WHERE your_special_condition
si aucune ligne n'est retournée à partir de select (parce que votre condition spéciale est false), aucun insert ne se produit.
en utilisant votre schéma de question (en supposant que votre id
la colonne est auto_increment
):
insert into orders (product_id, qty)
select 2, 20
where (SELECT qty_on_hand FROM products WHERE id = 2) > 20;
ceci insérera aucune ligne s'il n'y a pas assez de stock disponible, sinon cela créera la ligne de commande.
Belle idée btw!
Essaie:
INSERT INTO orders(product_id, qty)
SELECT 2, 20 FROM products WHERE id = 2 AND qty_on_hand >= 20
Si un produit avec id
égal 2
et les qty_on_hand
est supérieur ou égal à 20
pour ce produit, alors un insert se produira avec les valeurs product_id = 2
et qty = 20
. Sinon, aucun insert ne se produira.
Remarque:: si votre ID produit est unique, vous pouvez ajouter un LIMIT
clause à la fin du SELECT
déclaration.
vous résolvez probablement le problème de la mauvaise façon.
si vous avez peur que deux opérations de lecture se produisent en même temps et donc qu'une opération fonctionne avec des données périmées, la solution est de utiliser des serrures ou des transactions.
pour la requête faire ceci:
- table de verrouillage pour lire
- tableau
- mettre à jour le tableau
- déverrouille la serrure
pas sûr de la concurrence, vous aurez besoin de lire sur le verrouillage dans mysql, mais cela vous permettra d'être sûr que vous prenez seulement 20 articles si 20 articles sont disponibles:
update products
set qty_on_hand = qty_on_hand - 20
where qty_on_hand >= 20
and id=2
Vous pouvez alors vérifier combien de lignes ont été affectées. Si aucun n'était affecté, vous n'aviez pas assez de stock. Si une rangée a été affectée, vous avez effectivement consommé le stock.