4

「バリアディック」が実際に正しい言葉かどうかはわかりませんが、値のリストを取ることができるものについて話しているIN(). 長い間 DBI を使用してきた場合は、おそらく次のことを試みたことがあるでしょう:

(注: 簡潔にするために、すべての例は非常に単純化されています)

my $vals = join ', ', @numbers;
my $sth = $dbh->prepare( "SELECT * FROM mytbl WHERE foo IN( ? )" );
$sth->execute( $vals );     # doesn't work

?私の知る限り、DBI プレースホルダーは単にこの種の悪ふざけをサポートしていません。

これにより、次のようなことをすることになります。

my $sth = $dbh->prepare( "SELECT * FROM mytbl WHERE foo IN ( $vals )" );

これはそれほど恐ろしいことではありませんが、今日私が書いたような関数を考えてみてください。この関数は、IN句と値のリストを含む任意の SQL を受け入れる必要があります。

sub example { 
    my $self = shift;
    my ( $sql, @args ) = @_;

    my $vals = join ', ', @args;
    $sql =~ s/XXX/$vals/;    <---- # AARRRGHGH
    my $sth = $self->dbh->prepare( $sql );
    ...
}

これは最終的に次のようなものによって呼び出されます

my $sql = "SELECT * FROM mytbl WHERE foo IN( XXX ) AND bar = 42 ORDER BY baz";
my $result = $self->example( $sql, @quux );

これは私の美的感覚を本当に傷つけます。プログラムでカスタム SQL を構築することは、それだけでも十分に大きな苦痛です。必要がなければ、SQL 文字列を正規表現する道をたどりたくありません。

より良い方法はありますか?

4

5 に答える 5

5

純粋な DBI から抜け出し、いくつかのモジュールを使用することを気にしない場合は、例としてSQL::Abstractを見てみましょう。 SQL::Abstractは、Perl ハッシュを取り、それをwhereに変えることができます。

my $sql  = SQL::Abstract->new;
my @numbers = (1 .. 10);
my ($stmt, @bind) = $sql->where({foo => {'in', \@numbers}});
# $stmt is " WHERE ( foo IN ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) )"
# @bind contains the values 1 through 10.
于 2009-10-30T14:51:49.047 に答える
5

なぜだめですか:

  my $sql = "SELECT * FROM mytbl WHERE foo IN(" . join(',', ('?')x@quux) . ") AND bar = 42 ORDER BY baz";
  my $sth = $dbh->prepare($sql);
  $sth->execute(@quux);
于 2009-10-30T00:25:16.590 に答える
5

思考の糧。

DBIx::Simpleは、二重の疑問符プレースホルダーを使用して、このタイプのものの構文を提供します:

$db->query( 'SELECT * FROM mytbl WHERE foo IN ( ?? )', @args );

また、SQL::Abstractは強力ですが、抽象化によって最適な SQL が得られないことがあります。

于 2009-10-30T00:24:32.603 に答える
3

sprintfこのような状況で便利です:

my $sth = $dbh->prepare( 
    sprintf(
        'SELECT * FROM mytbl WHERE foo IN( %s )',
        join(',', ('?') x @numbers) )
);
于 2009-10-30T00:33:11.817 に答える
2

プレースホルダーとバインド値を使用するのが面倒な場合は、常にDBI::quote().

my $sql = sprintf 'SELECT * FROM mytabl WHERE foo IN ( %s )',
     join( ',', map { $dbh->quote( $_ ) } @args );
于 2009-10-30T10:05:19.077 に答える