DBIモジュールでは、プレースホルダを使う場合、基本的な記述は下記のようになる。
1 2 3 4 5 6 7 8 |
: # DB接続、SQL組み立て処理 : my $sth = $dbh->prepare("$sql"); $sth->bind_param(1, $value); # 第三引数に値のデータタイプも指定可能 : # 後処理 : |
んで、SQL分にWHERE句を含んでいる場合で、条件をINで複数指定している場合、
1 2 3 |
my $sql = "SELECT * FROM table_name WHERE column_name IN (?)"; my $sth = $dbh->prepare("$sql"); $sth->bind_param(1, "あ, い, う"); |
でいけると思いきや、値の最初の要素(カンマで区切った一番最初の値=「あ」)のみプレースホルダに代入されて処理されてしまう。つまり、
1 2 3 |
my $sql = "SELECT * FROM table_name WHERE column_name IN (?)"; my $sth = $dbh->prepare("$sql"); $sth->bind_param(1, "あ"); |
と同じ結果となってしまう。
どうやらカンマで連結した文字列を渡しても、配列要素とみなされるようだ。
なので、条件の数分だけ、プレースホルダを作り指定してやる必要がある。
単純に書くと、
1 2 3 4 5 |
my $sql = "SELECT * FROM table_name WHERE column_name IN (?,?,?)"; my $sth = $dbh->prepare("$sql"); $sth->bind_param(1, "あ"); $sth->bind_param(2, "い"); $sth->bind_param(3, "う"); |
てな感じ。
現実的にはINの条件数は動的になると思うので、うちでは下記のような感じで処理している。
・DB処理用ファイル(database.pl)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
package database; : # DB接続処理 : sub db_exec { my($sql, $bind) = @_; our $sth; my $exec; $sth = $db::dbh->prepare($sql) || die $db::dbh->errstr(); if($bind){ my $el = 1; map {$sth->bind_param($el,$$_{value},$$_{type}); $el++;} @$bind; } $exec = $sth->execute() || die $sth->errstr(); } |
・呼び出し元
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
requare database.pl; : my @in = (あ, い, う); &database::db_exec(" SELECT * FROM table_name WHERE column IN (". join(',', map{'?'} @in ).") ", [ ( map {+{ value => $_ }} @in ) # さらにプレースホルダがある場合はここに ,{ value => 'abc' } # のように書く ] #↑ +{...}はハッシュのリファレンスを示す ); : |
PHPでもフレームワークによってここの処理が違ったりするので注意が必要。