Есть ли привязка параметров SQL для массивов? - PullRequest
19 голосов
/ 05 февраля 2009

Существует ли стандартный способ связывания массивов (скаляров) в запросе SQL? Я хочу связать предложение IN, например:

SELECT * FROM junk WHERE junk.id IN (?);

Я использую Perl::DBI, который приводит параметры к скалярам, ​​поэтому я получаю бесполезные запросы, такие как:

SELECT * FROM junk WHERE junk.id IN ('ARRAY(0xdeadbeef)');

Уточнение: Я поместил запрос в его собственный файл .sql, поэтому строка уже сформирована. Там, где в ответах упоминается создание строки запроса динамически, я, вероятно, вместо этого буду выполнять поиск и замену.

Редактировать: Этот вопрос является своего рода дубликатом Параметризация предложения SQL IN? . Первоначально я думал, что он должен быть закрыт как таковой, но похоже, что он накапливает некоторую хорошую специфичную для Perl информацию.

Ответы [ 8 ]

13 голосов
/ 05 февраля 2009

Если вам не нравится карта, вы можете использовать оператор 'x':

my $params = join ', ' => ('?') x @foo;
my $sql    = "SELECT * FROM table WHERE id IN ($params)";
my $sth    = $dbh->prepare( $sql );
$sth->execute( @foo );

Скобки нужны вокруг «?» потому что это заставляет 'x' находиться в контексте списка.

Прочтите «perldoc perlop» и найдите «Двоичный« x »» для получения дополнительной информации (это в разделе «Мультипликативные операторы»).

12 голосов
/ 05 февраля 2009

Вы указываете «это SQL для запроса с одним параметром» - это не будет работать, если вам нужно много параметров. Конечно, иметь дело с болью. Два других варианта того, что уже было предложено:

1) Используйте DBI-> quote вместо заполнителей.

my $sql = "select foo from bar where baz in ("
           . join(",", map { $dbh->quote($_) } @bazs)
           . ")";
my $data = $dbh->selectall_arrayref($sql);

2) Используйте ORM, чтобы делать такие вещи низкого уровня для вас. DBIx :: Class или Rose :: DB :: Object, например.

9 голосов
/ 05 февраля 2009

Я делаю что-то вроде:

my $dbh = DBI->connect( ... );
my @vals= ( 1,2,3,4,5 );
my $sql = 'SELECT * FROM table WHERE id IN (' . join( ',', map { '?' } @vals ) . ')';
my $sth = $dbh->prepare( $sql );
$sth->execute( @vals );
6 голосов
/ 05 февраля 2009

И еще один способ построения SQL - использовать что-то вроде SQL :: Abstract ....

use SQL::Abstract;
my $sql    = SQL::Abstract->new;
my $values = [ 1..3 ];
my $query  = $sql->select( 'table', '*', { id => { -in => $values } } );

say $query;   # => SELECT * FROM table WHERE ( id IN ( ?, ?, ? ) )
4 голосов
/ 05 февраля 2009

При обычном DBI вам придется создавать SQL самостоятельно, как предложено выше. DBIx :: Simple (оболочка для DBI) делает это автоматически для вас, используя '??' Обозначения:

$db->query("select * from foo where bar in (??)", @values);
2 голосов
/ 05 февраля 2009

В Python я всегда заканчивал тем, что делал что-то вроде:

query = 'select * from junk where junk.id in ('
for id in junkids:
  query = query + '?,'
query = query + ')'

cursor.execute(query, junkids)

... который по сути строит запрос с одним '?' за каждый элемент списка.

(и если там есть и другие параметры, вам нужно убедиться, что вы правильно выстроили строки при выполнении запроса)

[отредактируйте, чтобы сделать код более простым для понимания людей, не являющихся питонами. Существует ошибка, при которой запрос будет иметь дополнительную запятую после последней?, Которую я оставлю, потому что ее исправление просто затуманивает общую идею]

0 голосов
/ 31 мая 2017

Использование

SELECT * FROM junk WHERE junk.id = ANY (?);

вместо

0 голосов
/ 05 февраля 2009

Я использую DBIx :: DWIW . Он содержит функцию с именем InList (). Это создаст ту часть SQL, которая необходима для списка. Однако это работает, только если у вас есть все ваши SQL в программе, а не снаружи в отдельном файле.

...