我不知道“variadic”实际上是否是正确的词,但我所说的是可以采用值列表的内容,例如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字符串。
有更好的方法吗?
答案 0 :(得分:5)
深思熟虑。
DBIx::Simple使用双问号占位符为
提供了此类事物的语法$db->query( 'SELECT * FROM mytbl WHERE foo IN ( ?? )', @args );
此外,SQL::Abstract功能强大,但我发现有时抽象不会产生最佳SQL。
答案 1 :(得分: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);
答案 2 :(得分:5)
如果你不介意打破纯DBI并使用某些模块,我会看一下你的例子SQL::Abstract。 SQL::Abstract可以使用Perl哈希并将其转换为where
clause。
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.
答案 3 :(得分:3)
sprintf
很方便:
my $sth = $dbh->prepare(
sprintf(
'SELECT * FROM mytbl WHERE foo IN( %s )',
join(',', ('?') x @numbers) )
);
答案 4 :(得分:2)
如果使用占位符和绑定值变得笨拙,则总是DBI::quote()
。
my $sql = sprintf 'SELECT * FROM mytabl WHERE foo IN ( %s )',
join( ',', map { $dbh->quote( $_ ) } @args );