如何在Perl的DBI中使用占位符来实现可变参数SQL函数?

fri*_*edo 4 sql perl dbi

我不知道"variadic"实际上是否是正确的词,但我在谈论可以采用一系列值的事情,比如IN().如果您已经使用DBI很长时间,您可能尝试这样做:

(注意:为简洁起见,所有示例都非常简化)

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

DBI占位符根本不支持这些类型的恶作剧,?据我所知,它是每个或不需要的单个值.

这导致我最终做了类似的事情:

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

这不是那么可怕,但考虑一个函数,就像我今天写的一样,必须接受一些带有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 );
    ...
}
Run Code Online (Sandbox Code Playgroud)

这最终会被看起来像的东西调用

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

这真的冒犯了我的审美感.以编程方式构建自定义SQL是一个非常大的痛苦; 如果我不需要,我不想走下去修复我的SQL字符串的道路.

有没有更好的办法?

mar*_*ton 5

值得深思.

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

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

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


Jos*_*ams 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);
Run Code Online (Sandbox Code Playgroud)


Jac*_* M. 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.
Run Code Online (Sandbox Code Playgroud)