2012-01-09 16 views
1

私が取り組んでいるプロジェクト内のループでデータベースへのアクセスを避けようとしています。 SQLでうまくやっているわけではありませんが、私はこれにアプローチする最善の方法が不明です。効率的なSQLの更新複数の行を1つのSQL文で更新し、ループを回避する

私は複数の在庫場所/場所を選択した販売手順で在庫データベースを更新しています。

したがって、これは私がやっていることです。

のように、それが行くように各製品のピックの位置をループと数量を更新し、その後、製品IDのをループ:この作品もちろん

が、それはすべての株式の新しいデータベース接続を開いています場所は、すべてのアイテムに適用されます。

これをどのようにして1つの更新ステートメントにするのですか?

http://www.karlrixon.co.uk/writing/update-multiple-rows-with-different-values-and-a-single-sql-query/

リンクは私が後だものに非常に近い私を取得することを、私は思うが、私は動的にSQL文を作成し、どのケースに二つの条件を追加する方法は100%を確認していません。

は、私のようなSQL文の何か構築する必要があります:

UPDATE stockLevels 
SET stockLevel= CASE id 
    WHEN '"& wProductId &"' AND stockLocation='"& thisLocation &"' THEN `stockLevel` - '" & thisQty & "' 
    WHEN '"& NEXTwProductId &"' AND stockLocation='"& NEXTthisLocation &"' THEN `stockLevel` - '" & NEXTthisQty & "' 
END 

をしかし、私はCASEの2番目のパラメータを追加していた場合、それは修正しません!

いつものように、私はMySQLとVB.NETを使用しています。

答えて

1

CASE式は構文的には正しくありません。

CASEの式は2種類ありますが、お互いにほとんど同じですが、構文が少し異なります。

CASE 
    WHEN condition1 THEN result1 
    WHEN condition2 THEN result2 
    ... 
    ELSE result_else 
END 

そして、あなたは、本質的にCASEこれら2種類のミックスしようとしていた。

一つは、このような

CASE expr 
    WHEN value1 THEN result1 
    WHEN value2 THEN result2 
    ... 
    ELSE result_else 
END 

他のルックスの形態を有します。 (私はあまり間違っていないよ場合、また検索CASEと呼ばれる)

あなたはおそらく第二いずれかを使用する必要があります。そこには一致しませんし、場合CASEは何ELSE一部を持っていないことを

... 
CASE 
    WHEN id = '"& wProductId &"' AND stockLocation='"& thisLocation &"' THEN ... 
    WHEN id = '"& NEXTwProductId &"' AND stockLocation='"& NEXTthisLocation &"' THEN ... 
... 

注意を、その結果、そうでない場合は、このようなELSE一部を使用し、NULLなるので、あなたはすべてのケースを紹介してきたことを確認します。

ELSE `stocklevel` 

すなわちCASEは更新される列の元の値に評価され、最後に更新は行われません。

+0

ああ、わかりました。文字通り、ケースの開始時に列名を指定しないケースです'ステートメント。それでは、2つのパラメータで 'case'を実行できますか?それは簡単です!私が持っていた構文が間違っていることを知っていましたが、正しい方法を知らなかったのです!ありがとう! a'rからの回答は、SQLステートメントが非常に長くなる可能性があるという点では有効です。私の場合、たぶん20種類以上の製品ラインを扱っているわけではないでしょう。ほとんどの場合、10未満である可能性があります。このケースを使用することがこの状況に最適な方法でしょうか? –

+0

20行以下の場合、CASEの解決策は私にとっては十分に可能なようです。それでも、私は一般的にはより良いアイデアが好きです。あなたは、今後もっと多くの製品ラインを扱わないかどうかは絶対に確信していないので、少なくとも、a'rの提案を念頭に置いておきたいと思うかもしれません。ポイント)。 –

+0

ありがとうございます。私はこれが私が最初に探していたものなので、この答えを受け入れるつもりですが、私は@ a'rがより良い長期的解決策を持っていると思っています。私はテンポラリテーブルを使ったことがないので、今のところそれを恥ずかしく思っています! –

5

例のset句にcase文を使用することは、いくつかの理由で理想的ではありません。

  • データベースは多数の更新のためのクエリのサイズが過剰になる
  • 効率的にクエリを実行するのに役立つ句(このような1000行の更新を検討)
  • あなたが手動で実施しているところなしありjoin - データベースは、あなたよりも効率的にこれを行うことができます。
  • このようなクエリのデバッグも難しいです。

代わりに、あなたは最初あなたが実際に改善を行う必要があるかどうかを確認するために、時間的なアプローチでアップデート1のパフォーマンスを測定する必要があります。

パフォーマンスの向上が必要な場合は、更新プログラムを一括して一時テーブルに挿入する方法をお勧めします。適したテーブルには、次の列があります:

INSERT INTO temp_stock_updates 
    (wProductID, stockLocation, newStockLevel) 
VALUES 
    (?,?,?), (?,?,?), (?,?,?), ... 

そして、単一の更新はメインテーブルを更新するために実行されます。

wProductID, stockLocation, newStockLevel 

更新は、次のMySQLの構文を使用して挿入バルクすることができます。このクエリは次のようになります。

UPDATE stockLevels s 
    JOIN temp_stock_updates u USING (wProductID, stockLocation) 
SET 
    s.stockLevel = u.newStockLevel 
+0

OK、アドバイスありがとうございます。私は100%確信しているわけではありませんが、一度に1つの方法はこの場合悪いですが、私は確かに前に同様の状況で問題があった。このアプリケーションでは、一度に10〜20行以上、最大3/4の場所を処理する可能性は低いので、80ループになる可能性があります。推奨される一時テーブルのアプローチを拡張できますか?私は何が起こっているのか分からないのですか? –

+0

@ JamieHartnoll、私は一時テーブルアプローチのためのいくつかの追加クエリを追加しました。 –

+0

a'rおそらくあなたはここで最高の解決策を得ていると思いますが、私が受け入れたものが直接質問に答えるとすぐに実装することができました。しかし、あなたのソリューションはより長期的に見えます。私は一度もテンポラリテーブルを使用したことがないし、作成する方法もわからないので、今私が知っているものに固執しています!とにかくありがとう! –

関連する問題