Ответ 1
Это должно динамически строить запрос в соответствии с количеством элементов в вашем массиве
my @list =(1,2,3,4,5);
my $sql ="select * from table where ID in (@{[join',', ('?') x @list]})";
У меня есть этот запрос 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
документация:
Кроме того, заполнители могут представлять только одиночные скалярные значения. Например, следующий оператор не будет работать должным образом для более чем одного значения:
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);
Если вы используете 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);
Если вы переключитесь на DBIx:: Simple, вы можете просто сказать:
$db->query('INSERT INTO foo VALUES (??)', $foo, $bar, $baz);
?? Значит "столько, сколько необходимо"
Edit:
На самом деле, я был слишком оптимистичен: "Если в запросе присутствует строка (??), она заменяется списком столько вопросительных знаков, как @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;
}
Если вы не знаете точное количество элементов, вы не можете использовать заполнители. Попробуйте следующее:
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)";
Я нашел верный способ для этого обобщить все приведенные выше советы. Мой запрос на производство (здесь я опубликовал гораздо более простую версию) использует 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 ..............
}
Образец результата:
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
Я очень благодарен всем, кто разместил свои идеи здесь, что, наконец, заставило меня найти правильный способ сделать это. Я думаю, что это довольно распространенная проблема.