2011-07-28 23 views
21

まず、ここで問題の簡潔な概要です:MySQLのINSERT IF(カスタムif文)

は条件付きでINSERTステートメントを実行することが可能ですか?これに似 何か:

IF(expression) INSERT... 

は今、私は、ストアドプロシージャでこれを行うことができます知っています。 私の質問です:私は私のクエリでこれを行うことはできますか?


なぜ、私はそれをしたいのですか?

は、我々は以下の2つのテーブルを持っていると仮定しましょう:

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

それでは、20体のブードゥー人形の注文(製品ID 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というクエリが実行されます。
これまでのところとても良いです。


ただし、並行性に問題があります。
正確に同じ時刻ので2つの注文が届いた場合、その注文のいずれかが注文に入る前に、数量を読み込んでいる可能性があります。 これで注文は両方とも行われますので、qty_on_handを超えています。だから、戻って質問のルートに



それは我々が一つにこれらのクエリの両方を組み合わせることができるように、条件付きでINSERTステートメントを実行することは可能ですか?

私は多くを検索しました。条件付きINSERTの唯一のタイプはON DUPLICATE KEYでしたが、これは当然当てはまりません。

答えて

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

特別な条件がfalseであるため、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!

+0

@Bohemian:2つのSELECT文は必要ありません。 1つで十分です。私の答えを見てください。 :) – Shef

+0

本当ですが、私は私の*一般的な*パターンにマッチさせようとしていました。私はあなたの答えが好きです... +1 – Bohemian

+0

@ジョセフ・シルバー:何をするか???その減算はどこにありますか?減算と正規化とは何が関係していますか? :D上記のクエリは、私と比較して2つの「SELECT」文で構成されていることを理解していますか? (あなたの答え、またはあなた、ボヘミアンに対して何もない)。 – Shef

2

おそらく間違った方法で問題を解決しています。

2つの読み取り操作が同時に行われるため、古いデータが処理される恐れがある場合、解決方法はです。です。

は、クエリがこれを行う有無:

  • ロックテーブルを読み込むため
  • 読み取りテーブル
  • 更新テーブル
  • 同時実行についてのレリーズロックが
+0

私はロックが最良の解決策であるとは確信していません。重大なパフォーマンス上の問題を引き起こす可能性があります。 –

2

わからない、あなたが必要ですmysqlのロックを読み取ることができますが、これにより、20項目が利用可能である場合には、20項目しか取らないことが保証されます:

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

影響を受けた行の数を確認できます。影響を受けるものがなければ、十分な在庫がありませんでした。 1行が影響を受けていれば、株式を効果的に消費しています。

16

試行:

2に等しい id有する製品が存在し、 qty_on_handこの製品の 20以上である
INSERT INTO orders(product_id, qty) 
SELECT 2, 20 FROM products WHERE id = 2 AND qty_on_hand >= 20 

場合、インサートは値product_id = 2、及びqty = 20で起こるであろう。それ以外の場合、挿入は行われません。

:あなたのプロダクトIDがノート一意である場合は、SELECT文の末尾にLIMIT句を追加したい場合があります。

+0

どのようにこれを否定しますか? – user2340939

+0

1つの方法は、最後に次のものを追加することです。HAVING COUNT(*)= 0。 – user2340939