- ベストアンサー
Perlでexecuteをまとめて実行したい
以前似たような質問をしたモノですが、 Perl(cgi)ファイルからテーブル内の一定の項目をDELETEしようとしています 具体的にいうと、多数あるチェックボックスにチェックされた項目のみを削除するプログラムで、チェックされた値はハッシュに格納し読み込み、削除をしています。 foreach $key (keys %hash) { # 取り出した値を$noに代入 $no = $hash{$key}; # SQL発行 $sql = $db->prepare("DELETE FROM テーブル名 WHERE レコード指定名='$no'"); # SQL実行 $sql->execute; } もしくは # ハッシュに入れた値をカウント $n = keys( %hash ); # プレースホルダを使用し削除の実行 $sql = $db->prepare("DELETE FROM テーブル名 WHERE レコード指定名=?"); for($i=0; $i<$n; $i++) { # SQL実行 $sql->execute(@hash{$i}); } 上記の方法でどちらも問題なく実行できているのですが、ご覧のようにハッシュに格納されている数だけ$sql->execute;を実行しているため効率が悪い、と担当者から指摘をうけました。 少しでもマシンの負担を軽くし、スムーズにするためにexecuteをまとめて実行することを求められています。 selectcol_arrayref などを使う方法などを検索できたのですが、具体的なサンプルがないとまだ分からない初心者で、上記のプログラムに当てはめる方法が分からないでいます。 ご教授のほどよろしくお願いします。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
perlのmysql 用モジュールの方は使ったことはないけど、phpと同様だろうと考えて回答してみます。 せっかくプレースホルダーを使ったsql文が使えているのだから、プレースホルダーに入れるようにすれば、データが数値か文字列かのチェックやエスケープ対策も出来るはずです。 # ハッシュに入れた値をカウント $n = keys( %hash ); # プレースホルダーを使用し削除用 sql文 作成 $sql = $db->prepare("DELETE FROM テーブル名 WHERE カラム名 in (". join(',', map{'?'}[1..$n]) . ")"); ### データバインド用の関数があるはずなので、データ配列と、データ型指定用配列または文字列をセットする。 ### 関数名、引数の与えかたは使ってるモジュールのドキュメントを調べて下さい。 $sql->?bind?( データ、カラム型指定 ); # sql 実行 $sql->execute();
その他の回答 (2)
- nora1962
- ベストアンサー率60% (431/717)
> ループで文字を連結させていく方法が思いつかなかったので、join関数を > 使い強引に文字を連結させてみました。 > 今回は、値が全て数値だったのでこの方法でできましたが、値が文字列 > だった場合join関数では『”(ダブルコーテーション)』で区切るわけでは > ないのでできなくなります。 joinする前にmap関数でシングルクォートでくくるというのはどうですか。 @a = ( 'a','b','c','d' ); $b = join( ",", map{ "'".$_."'"; } @a ); $sql = "select * from テーブル where カラム in ( $b )"; みたいに
お礼
nora1962様、回答ありがとうございます。 回答頂いたやり方で文字列も解決できそうです。 プログラムを勉強し始めて2ヶ月たつのですが、今回のような関数の見つけ方が未熟で皆さんにお手数かけています。 早く自分で解決できるように力を付けたいと思います。 ありがとうございました。
- chukenkenkou
- ベストアンサー率43% (833/1926)
「=」条件でprepare&executeするのでなく、in条件を指定すればいいのでは? ループ内ではSQL文の組み立て(in条件の値リストをどんどん文字連結していく)を行い、ループから抜けた後にprepareとexecuteするといった方法です。 「select ~ from ~ where 列名 in(値1,値2, ~ ,値n)」といったSQLを作ることになります。
補足
chukenkenkou様、ご返答ありがとうございます。とても助かりました。 下記のプログラムで一応動かすことができました。 @s_del = values(%hash); # ハッシュの値のみを全て配列に代入 @s_del = join( ',', @s_del); # 配列を連結 $sql = $db->prepare("DELETE FROM テーブル名 WHERE レコード名 IN (@s_del)"); $sql->execute; ループで文字を連結させていく方法が思いつかなかったので、join関数を使い強引に文字を連結させてみました。 今回は、値が全て数値だったのでこの方法でできましたが、値が文字列だった場合join関数では『”(ダブルコーテーション)』で区切るわけではないのでできなくなります。 ループ内でSQL文の組み立て(in条件の値リストをどんどん文字連結していく)方法として何かいい方法はあるでしょうか?
お礼
hrm_mmm様、回答ありがとうございます。 かなり勉強になるソースありがとうございます。 map関数はもちろん、このようなプレースホルダーの効率の良い使用方法があるんですね。 参考にさせて頂きます。 ちなみに、今回のようなSQL文をいろいろ応用し作成するやり方を知るいいサイト、もしくは参考書はあるのでしょうか? 経験し積み重ねていくしかないのでしょうか? もし、参考見聞があれば教えて下さい。