perl DBI和占位符

时间:2011-10-22 18:19:15

标签: perl dbi

我有这个查询select * from table where ID in (1,2,3,5...)

如何使用占位符与DBI构建此查询?

例如:

my @list = (1, 2, 3, 4, 5);
my $sql = "select * from table where ID in (?)";

$sth->prepare($sql);
$sth->execute();

我应该发送什么参数来执行?它是由,或其他东西分隔的列表或字符串吗?

7 个答案:

答案 0 :(得分:28)

这应该根据数组中项目的数量动态构建查询

my @list =(1,2,3,4,5);
my $sql ="select * from table where ID in (@{[join',', ('?') x @list]})";

答案 1 :(得分:11)

以这种方式是不可能的。您需要为数组中的每个项指定占位符:

my @list = (1,2,3,4,5);
my $sql = "select * from table where ID in (?,?,?,?,?)";

$sth->prepare($sql);
$sth->execute(@list);

如果您的@list不是固定大小,则需要使用适当数量的占位符构建$sql

答案 2 :(得分:6)

引用DBI documentation

  

此外,占位符只能表示单个标量值。例如,以下语句将无法按预期工作          对于多个值:

     SELECT name, age FROM people WHERE name IN (?)    # wrong
     SELECT name, age FROM people WHERE name IN (?,?)  # two names

重写为:

my $sql = 'select * from table where ID in ( ?, ?, ?, ?, ? )';
$sth->prepare($sql);
$sth->execute(@list);

答案 3 :(得分:2)

如果您使用DBI使用DBD :: Pg驱动程序访问PostgreSQL数据库,您可以使用:

my @list = (1, 2, 3, 4, 5);
my $sql = "select * from table where ID = ANY(?::INT[]);";

$sth->prepare ($sql);
$sth->execute (\@list);

答案 4 :(得分:1)

如果切换到DBIx::Simple,您只需说:

$db->query('INSERT INTO foo VALUES (??)', $foo, $bar, $baz);

??意味着“尽可能多的”

修改

实际上,我有点过于乐观了:“如果查询中存在字符串(??),则会将其替换为与@values一样多的问号列表。” < / p>

所以这似乎不起作用:

$db->query( "SELECT * FROM foo WHERE id IN (??) AND stuff=?", @ids, $stuff )

虽然仍然有用..

好奇的是,模块中的代码是:

# Replace (??) with (?, ?, ?, ...)
sub _replace_omniholder {
  my ($self, $query, $binds) = @_;
  return if $$query !~ /\(\?\?\)/;
  my $omniholders = 0;
  my $q = $self->{dbd} =~ /mysql/ ? $quoted_mysql : $quoted;
  $$query =~ s[($q|\(\?\?\))] {
    $1 eq '(??)'
    ? do {
        Carp::croak('There can be only one omniholder')
            if $omniholders++;
        '(' . join(', ', ('?') x @$binds) . ')'
    }
    : $1
  }eg;
}

答案 5 :(得分:1)

除非您知道元素的确切数量,否则不能使用占位符。试试这个:

my @list = (1, 2, 3, 4, 5);  # any number of elements
my $in = join(',', map { $dbh->quote($_) } @list);
my $sql = "select * from table where someid IN ($in)";

答案 6 :(得分:0)

我找到了一个确定的方法来总结所有上述建议。我的生产查询(我在这里发布了一个更简单的版本)使用IN&lt;&gt;,其中代码及其数量都未知。它可以是单个代码(例如FIN),也可以是一系列代码(FITLC FITLD FITLU FITSC FITSD FITSU MDYLC MDYLD MDYLU)。某些函数将其作为列表返回。

实现这一目标的代码是

            @codes =  get_muni_evcode( $category );
            my $in = join( ', ', ('?') x @codes );
            print "\n\nProcessing Category: $category --> Codes: @codes   .. in: $in\n";

            my $sql = "select distinct cusip9 
            from material_event 
            where event_date between (trunc(sysdate) - 1) + 2/3 and trunc(sysdate) + 2/3 
            and event_code in ($in)";
            my $sth2 = $dbh->prepare($sql);
            $sth2->execute( @codes );

            while (my $s2 = $sth2->fetchrow_hashref('NAME_lc'))
            {
                    my $cusip9 = $s2->{cusip9};
                    print "$cusip9\t";
                   .................. further processing ..............

            }

结果样本:

Processing Category: RatingChange --> Codes: FITLC FITLD FITLU FITSC FITSD FITSU MDYLC MDYLD MDYLU MDYSC MDYSD MDYSU SPLD SPLPR SPLU SPSD SPSPR SPSU .. in: ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? 359496HQ2 359496GB6 359496GH3 359496GL4 359496HU3 359496HS8 359496HA7 359496HF6 359496GM2 359496HM1 359496HR0 359496HT6 359496GY6 359496GJ9 359496HL3 359496GU4 359496HK5 359496HN9 359496HP4 359496GW0 359496GZ3 359496HC3 359496GC4 359496GK6 359496GP5 359496GV2 359496GX8 359496GN0

我非常感谢在这里发表意见的所有人,这终于让我找到了正确的方法。我认为这一定是一个非常普遍的问题。