3

How do I bind a variable to a SQL set for an IN query in Perl DBI?

Example:

my @nature = ('TYPE1','TYPE2'); # This is normally populated from elsewhere
my $qh = $dbh->prepare(
      "SELECT count(ref_no) FROM fm_fault WHERE nature IN ?"
) || die("Failed to prepare query: $DBI::errstr");

# Using the array here only takes the first entry in this example, using a array ref gives no result
# bind_param and named bind variables gives similar results
$qh->execute(@nature) || die("Failed to execute query: $DBI::errstr");

print $qh->fetchrow_array();

The result for the code as above results in only the count for TYPE1, while the required output is the sum of the count for TYPE1 and TYPE2. Replacing the bind entry with a reference to @nature (\@nature), results in 0 results.

The main use-case for this is to allow a user to check multiple options using something like a checkbox group and it is to return all the results. A work-around is to construct a string to insert into the query - it works, however it needs a whole lot of filtering to avoid SQL injection issues and it is ugly...

In my case, the database is Oracle, ideally I want a generic solution that isn't affected by the database.

Gert van den Berg
  • 2,448
  • 31
  • 41

1 Answers1

4

There should be as many ? placeholders as there is elements in @nature, ie. in (?,?,..)

my @nature = ('TYPE1','TYPE2');
my $pholders = join ",", ("?") x @nature;
my $qh = $dbh->prepare(
    "SELECT count(ref_no) FROM fm_fault WHERE nature IN ($pholders)"
) or die("Failed to prepare query: $DBI::errstr");
mpapec
  • 50,217
  • 8
  • 67
  • 127
  • Interesting approach... Doesn't work for named bind variables though... (I tried to simplify the example as much as possible, my full query has a few repeated variables where I'm using the Oracle style `:name` variables) (I wonder if you can mix `?` with the named type...) I'm still hoping there is a way to directly bind a set/list... – Gert van den Berg Jan 27 '15 at 11:36
  • AFAIK, you have to use only named placeholders for Oracle. – mpapec Jan 27 '15 at 11:44
  • 2
    That would be `my $pholders = join ", ", map ":$_", 1 .. @nature;` – mpapec Jan 27 '15 at 11:47
  • Quick note: No, you can't mix placeholder styles... I'm using `:nat$_` currently.. Filling it in a loop with bind_param, but that can probably be done with `map`'s block form... (Edit: Map seems to make sense mainly when worried about the result, so one line for is probably the relevant option) – Gert van den Berg Jan 27 '15 at 13:53
  • @Сухой27 - Nope, Oracle is perfectly happy with `?` placeholders. – Jim Davis Jan 27 '15 at 16:04
  • @JimDavis I think this is only due `DBD::Oracle` [implementation](http://search.cpan.org/~pythian/DBD-Oracle-1.30/Oracle.pm#Placeholders) – mpapec Jan 27 '15 at 17:40