Есть ли привязка параметров SQL для массивов?

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

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

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

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

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

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


person cdleary    schedule 04.02.2009    source источник
comment
Это обман известного вопроса. Дай хоть найду....   -  person Ray    schedule 05.02.2009
comment
Это также зависит от базы данных...   -  person Mitch Wheat    schedule 05.02.2009
comment
Прикольно - искал, но сам не нашел.   -  person cdleary    schedule 05.02.2009
comment
Взгляните на этот вопрос. Я не очень разбираюсь в perl, но если вы можете соединить массив вместе, чтобы он был в одной строке, вы, вероятно, могли бы заставить его работать. Или просто используйте ответ, получивший наибольшее количество голосов в этом вопросе.   -  person Ray    schedule 05.02.2009
comment
Нашел, но это не с массивами, но вы, возможно, сможете адаптироваться.   -  person Ray    schedule 05.02.2009


Ответы (8)


Вы указываете «это 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.

person Ask Bjørn Hansen    schedule 05.02.2009
comment
однако, с моей стороны, использование DBI-›quote не работает; я использовал $dbh-›quote; здесь $dbh из $dbh = DBI-›connect(DBI:mysql:$db:$host, $user, $pass); - person hetaoblog; 22.02.2013

Если вам не нравится карта, вы можете использовать оператор '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" и найдите "Binary "x"" для получения дополнительной информации (она находится в разделе "Мультипликативные операторы").

person Ovid    schedule 05.02.2009
comment
Откуда взялся @vals? Вы имеете в виду @foo? - person teambob; 25.03.2016
comment
teambob: да, я имел в виду @foo. Я изменил его. Спасибо! - person Ovid; 30.03.2016

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

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 );
person JDrago    schedule 05.02.2009
comment
@Dems, пример JDrago уже использует переменные связывания, поэтому ему не нужно ничего делать, чтобы предотвратить внедрение SQL. - person mpeters; 05.02.2009
comment
map { '?' } @vals проще ('?') x @vals - person ysth; 07.09.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 ( ?, ?, ? ) )
person draegtun    schedule 05.02.2009
comment
Я как раз собирался опубликовать это, и я определенно думаю, что это правильный ответ. Если вы не можете использовать ORM, по крайней мере, используйте что-то вроде SQL::Abstract (или, может быть, Fey). - person jrockway; 06.02.2009

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

$db->query("select * from foo where bar in (??)", @values);
person 8jean    schedule 05.02.2009
comment
Но тогда можете ли вы привязать параметры в другом месте в SQL? Я не понимаю, как вы могли связать параметры после ?? если вместо этого необязательно принимается ссылка на массив. - person cdleary; 14.02.2009
comment
Хороший вопрос. Если я правильно понимаю документы, у вас может быть либо несколько одиночных заполнителей, либо один «??», но не оба. - person 8jean; 18.02.2009

В python я всегда делал что-то вроде:

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

cursor.execute(query, junkids)

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

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

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

person John Fouhy    schedule 04.02.2009
comment
Конечно, если вы не беспокоитесь о SQL-инъекциях, вам вообще не нужны параметры. - person Ray; 05.02.2009
comment
@Ray: я не понимаю вашего комментария - он делает привязку параметров, просто добавляя соответствующее количество параметров для динамической привязки. - person cdleary; 05.02.2009
comment
хм.. так он и есть. Извините моя ошибка. - person Ray; 05.02.2009
comment
Без проблем. Просто хотел убедиться, что мы на одной волне. :-) - person cdleary; 05.02.2009
comment
Вот версия Perl: $params = '?, ' x scalar(@junk_ids); $query = 'SELECT * FROM junk WHERE junk.id IN (' . substr($params, 0, -2) . ');'; # Убираем запятую в конце. - person cdleary; 05.02.2009

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

person Peter Stuifzand    schedule 05.02.2009

Использовать

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

вместо

person Martin Janota    schedule 31.05.2017