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.

25
demandé sur Joseph Silber 2011-07-28 10:44:35

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!

42
répondu Bohemian 2011-07-28 07:16:20

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.

17
répondu Shef 2011-07-28 07:16:13

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
2
répondu Konerak 2011-07-28 06:52:56

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.

2
répondu My Other Me 2011-07-28 06:58:59