5

This is an addition to my solved question here: how to get array of zip codes within x miles in perl

OK, I have the array @zips. Now I am trying to use it in a query like this:

SELECT `club_name`,`city` FROM `table` WHERE `public_gig` = 'y' AND `zip` IN (@zips)
#I also tried syntax "IN ("@zips"), IN @zips and IN ('@zips')"

But, I cannot get it to work. (I am using placeholders and such as you see in my link above.)

I was able to get this to work:

$fzip=shift(@Zips);
$lzip=pop(@Zips);
SELECT `club_name`,`city` FROM `table` WHERE `public_gig` = 'y' AND `zip` BETWEEN $fzip AND $lzip

    ZIP | public_gig | start_time | fin_time | city       | club_name | and so on
  33416 | y          | 9pm        | 2am      | clearwater | beach bar | yada

But, for obvious reasons and some resemblance of accuracy, that is not really what I want. Just wanted to see if I could get SOMETHING working on my own.

Why can't I get the query to work with the zips in the array using IN?? Nothing is returned and there is no error.

There is actually a lot more in that query but, I left it all out to keep it short here.

I tried to figure it out by myself. Obviously, my learning capacity for the day is near peak.

Thanks for any help.

5 Answers 5

10

All of the examples posted here will screw up if any of your values contain single-quotes, don't use them.

Instead (assuming $dbh is the database handle for your mysql connection):

my $zip_string = join q{,}, map $dbh->quote($_), @zips;

and interpolate that.

Or, for something nice, but not half as outlandish as DBIx::Perlish: SQL::Abstract.

my $sqla = SQL::Abstract->new;
my ($sql, @bind) = $sqla->select(
  'table', 
  ['club_name', 'city'],
  {
    public_gig => y',
    zip => { -in => \@zips },
  }
);

$dbh->prepare($sql);
$dbh->execute(@bind);
# fetchrow etc.
Sign up to request clarification or add additional context in comments.

3 Comments

Leaving aside the "crack-fueled" part, the statement about "all of the examples" and single quotes is factually incorrect. :-)
Thank you. I do sterilize quite well and am using DBI amd placeholders but, your advice is taken quite seriously by me. I will continue to strive for better security. I will look into SQL::Abstract and see if I need to / am capable of convert(ing) my current queries. I will prob post another question with a working example of what I finally came up with. Thanks!
@Stephayne point is that constructing the in this way doesn't use placeholders, so you need to use proper quoting.
8

This can be done using placeholders, you just have to work around the limitation that each placeholder can only accept a single value. WHERE zip IN (?) won't work because you're (presumably) looking for more than one value (otherwise, why use IN?).

You can, however, easily build a statement on the fly with the correct number of placeholders:

#!/usr/bin/env perl

use strict;
use warnings;

my @zips = (12345, 54321, 90210);
my $stmt = "SELECT `club_name`,`city`
            FROM `table`
            WHERE `public_gig` = 'y' AND `zip` IN ("
           . join(', ', ('?') x @zips) . ')';

print "$stmt\n";

# Now just:
# my $sth = $dbh->prepare($stmt);
# $sth->execute(@zips);

1 Comment

This is very true -- it can become somewhat confusing if you're using it in a statement with more placeholders/bind values, but this works just great. And if it gets too complicated that's where something like SQLA will really help.
1

Alternatively, if you don't mind using weird CPAN modules, with DBIx::Perlish you can just say:

my @results = db_fetch {
   my $t: table;
   $t->public_gig eq "y";
   $t->zip  <-  @zips;
};

and it will do the right thing.

Full disclosure: I am the author of DBIx::Perlish.

Comments

-1

I don't know perl too much, but this looks like a simple SQL problem: why don't you just build the SQL IN clause from your array? You should get something like

AND zip IN ('zip 1', 'zip 2', '...')

I doubt just adding an array in perl will create the right strings for the SQL string ...

Comments

-6

You need to turn the array into a string of values seperated by commas. Try this :

my $zipcodes = join('\',\'',@zips);
SELECT `club_name`,`city` FROM `table` WHERE `public_gig` = 'y' AND `zip` IN ('".$zipcodes."');

3 Comments

Thank you @Sam Broad! Worked perfectly! Taking the extra time to use my vars really helped me out.
-1 any teaching code for DBI without placeholders makes Bobby Tables weep.
Snarky comments without pointers to docs explaining what you mean makes teachers weep.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.