[英]How can I use placeholders for variadic SQL functions with Perl's DBI?
I don't know if "variadic" is actually the right word, but I'm talking about things that can take a list of values, like IN()
. 我不知道“variadic”实际上是否是正确的词,但我在谈论可以采用值列表的事情,比如
IN()
。 If you've been working with DBI for long, you've probably tried to do this: 如果您已经使用DBI很长时间,您可能尝试这样做:
(Note: All examples extremely simplified for brevity) (注意:为简洁起见,所有示例都非常简化)
my $vals = join ', ', @numbers;
my $sth = $dbh->prepare( "SELECT * FROM mytbl WHERE foo IN( ? )" );
$sth->execute( $vals ); # doesn't work
DBI placeholders simply don't support these kinds of shenanigans, it's a single value for each ?
DBI占位符根本不支持这些类型的恶作剧,它们各自的价值是
?
or nothing, as far as I know. 或者根据我所知,什么也没有。
This leads me to end up doing something like: 这导致我最终做了类似的事情:
my $sth = $dbh->prepare( "SELECT * FROM mytbl WHERE foo IN ( $vals )" );
which isn't so horrible, but consider a function, like one I wrote today, that has to accept some arbitrary SQL with an IN
clause and a list of values 这不是那么可怕,但考虑一个函数,就像我今天写的一样,必须接受一些带有
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 );
...
}
This ends up getting called by stuff that looks like 这最终会被看起来像的东西调用
my $sql = "SELECT * FROM mytbl WHERE foo IN( XXX ) AND bar = 42 ORDER BY baz";
my $result = $self->example( $sql, @quux );
This really offends my sense of aesthetics. 这真的冒犯了我的审美感。 Building custom SQL programmaticly is a big enough pain as it is;
以编程方式构建自定义SQL是一个非常大的痛苦; I don't want to go down the road of regexing my SQL strings if I don't have to.
如果我不需要,我不想走下去修复我的SQL字符串的道路。
Is there a better way? 有没有更好的办法?
Food for thought. 值得深思。
DBIx::Simple offers a syntax for this type of thing using a double-question mark placeholder: DBIx :: Simple使用双问号占位符为这类事物提供语法:
$db->query( 'SELECT * FROM mytbl WHERE foo IN ( ?? )', @args );
Also, SQL::Abstract is powerful, but I find sometimes the abstractions don't result in optimal SQL. 此外, SQL :: Abstract功能强大,但我发现有时抽象不会产生最佳SQL。
Why not: 为什么不:
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);
If you don't mind breaking from pure DBI and using some modules, I'd take a look at SQL::Abstract for your example. 如果你不介意打破纯DBI并使用一些模块,我会看看你的例子中的SQL :: Abstract 。 SQL::Abstract can take a Perl hash and turn it into a
where
clause . 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.
sprintf
is handy in such situations: sprintf
在这种情况下很方便:
my $sth = $dbh->prepare(
sprintf(
'SELECT * FROM mytbl WHERE foo IN( %s )',
join(',', ('?') x @numbers) )
);
If using placeholders and bind values gets clumsy, there's always DBI::quote()
. 如果使用占位符和绑定值变得笨拙,那么总是有
DBI::quote()
。
my $sql = sprintf 'SELECT * FROM mytabl WHERE foo IN ( %s )',
join( ',', map { $dbh->quote( $_ ) } @args );
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.