Perl DBI и заполнители - PullRequest
       4

Perl DBI и заполнители

11 голосов
/ 22 октября 2011

У меня есть этот запрос 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 ]

28 голосов
/ 22 октября 2011

Это должно построить ваш запрос динамически в соответствии с количеством элементов в вашем массиве

my @list =(1,2,3,4,5);
my $sql ="select * from table where ID in (@{[join',', ('?') x @list]})";
11 голосов
/ 22 октября 2011

Это невозможно.Вам необходимо указать местозаполнитель для каждого элемента в вашем массиве:

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

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

Если ваш @list не является фиксированным размером, вам нужно построить $sql с соответствующим количеством заполнителей.

6 голосов
/ 22 октября 2011

Цитирование 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);
2 голосов
/ 25 декабря 2011

Если вы используете 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);
1 голос
/ 20 января 2014

Если вы не знаете точное количество элементов, вы не можете использовать заполнители. Попробуйте это:

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)";
1 голос
/ 03 ноября 2011

Если вы переключитесь на 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;
}
0 голосов
/ 04 августа 2015

Я нашел верный способ для этого, суммируя все вышеперечисленные советы.Мой производственный запрос (я разместил здесь гораздо более простую версию) использует 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

IЯ чрезвычайно благодарен всем, кто разместил здесь свои идеи, которые, наконец, заставили меня найти правильный способ сделать это.Я думаю, это довольно распространенная проблема.

...