我有以下查询语句: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();
我应该发送什么参数执行?它是由,
分隔的列表还是字符串,还是其他东西?
这将根据您的数组中的项目数量动态构建查询。
my @list =(1,2,3,4,5);
my $sql ="select * from table where ID in (@{[join',', ('?') x @list]})";
以那种方式是不可能的。你需要为数组中的每个项指定一个占位符:
my @list = (1,2,3,4,5);
my $sql = "select * from table where ID in (?,?,?,?,?)";
$sth->prepare($sql);
$sth->execute(@list);
如果你的@list
不是固定大小的,你需要使用正确数量的占位符构建$sql
。引用 DBI
文档:
Also, placeholders can only represent single scalar values. For example, the following statement won't work as expected for more than one value:
SELECT name, age FROM people WHERE name IN (?) # wrong SELECT name, age FROM people WHERE name IN (?,?) # two names
Rewrite to:
my $sql = 'select * from table where ID in ( ?, ?, ?, ?, ? )';
$sth->prepare($sql);
$sth->execute(@list);
如果你正在使用DBI来访问PostgreSQL数据库,使用DBD::Pg驱动程序,可以使用以下代码:
my @list = (1, 2, 3, 4, 5);
my $sql = "select * from table where ID = ANY(?::INT[]);";
$sth->prepare ($sql);
$sth->execute (\@list);
除非你知道元素的确切数量,否则你不能使用占位符。尝试这个:
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)";
如果你切换到DBIx::Simple,你只需要这样说:
$db->query('INSERT INTO foo VALUES (??)', $foo, $bar, $baz);
?? 的意思是“需要多少就用多少”。
编辑:
实际上,我有点过于乐观了:“如果查询中存在字符串 (??),它将被替换为与 @values 一样多的问号列表。”
所以这似乎行不通:
$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;
}
我找到了一种确保这个方法能够总结以上所有建议的方法。我的生产查询(我在这里发布了一个简化版本)使用IN <>,其中代码和它们的数量都是未知的。它可以是单个代码(例如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 ..............
}
结果样例:
处理类别:RatingChange --> 代码:FITLC FITLD FITLU FITSC FITSD FITSU MDYLC MDYLD MDYLU MDYSC MDYSD MDYSU SPLD SPLPR SPLU SPSD SPSPR SPSU .. 在: ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
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
我非常感激在这里发布他们的想法的所有人,最终让我找到了正确的方法来解决这个问题。我认为这应该是一个相当普遍的问题。
::INT[]
。只要id = ANY(?)
对我来说就可以了。 - Smylers