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

深思熟虑。

DBIx::Simple使用双问号占位符为此类事物提供语法:

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

此外,SQL::Abstract功能强大,但我发现有时抽象不会产生最佳 SQL。

于 2009-10-30T00:24:32.603 回答
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

如果您不介意脱离纯 DBI 并使用一些模块,我会为您的示例看一下SQL::AbstractSQL::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 回答
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 回答