more elegant way to construct SQL adding WHERE and using placeholders
Asked Answered
L

3

5

What is the best way to construct sql with various number of WHERE conditions ? My solution looks ugly:

my ($where, @values);
if ($phone_number)
{
    $where = 'AND pnone_number=?';
    @values = ($from, $till, $phone_number);
}
else 
{
    $where = '';
    @values = ($from, $till);
}
my $sql = 'SELECT * FROM calls WHERE time between ? AND ? '.$where.' ORDER BY time';
my $res = $dbh->selectall_arrayref($sql, undef, @values) or warn 'error';
Lanoralanose answered 20/5, 2013 at 7:57 Comment(1)
SQL::Maker would abstract away the SQL details.Jair
O
10

How about:

my $where = '';
my @values = ( $from, $till );

if ( $phone_number ) { 
    $where = 'AND phone_number=?';
    push @values, $phone_number;
}

That eliminates the need for your else clause.

You could also use something like SQL::Abstract.

use SQL::Abstract;

...

my ( $sql, @values ) = SQL::Abstract->new->select(
    'calls',                                                    # table
    '*',                                                        # columns
    { time => { '<=' => $till, '>' => $from },                  # where clause
      $phone_number ? ( phone_number => $phone_number ) : ( ),
    },
    'time'                                                      # order clause
);
Outsole answered 20/5, 2013 at 8:18 Comment(1)
DBIx::Class uses SQL::Abstract under the hood. $schema->resultset('Calls')->search({ time => {-between, [$from, $until]}, defined $phone ? (phone => $phone) : () }, { order_by => {-asc => 'time'} } )->allVanadium
F
1

1=1 is added for cases when $where would be epmty.

my $where = "AND time between ? AND ? ";
my @values = ($from, $till);

if ($phone_number) {
    $where .= 'AND pnone_number=? ';
    push @values, $phone_number;
}

my $sql = 'SELECT * FROM calls WHERE 1=1 $where ORDER BY time';
my $res = $dbh->selectall_arrayref($sql, undef, @values) or warn 'error';
Foulard answered 20/5, 2013 at 9:24 Comment(0)
C
0

Conditional list-include (aka "enterprise"):

my @values = ( $from,
               $till,
               ( $phone_number ) x !! $phone_number,
             );

my $sql = 'SELECT * FROM calls WHERE time between ? AND ? '
        . 'AND phone_number=?' x !! $phone_number
        . ' ORDER BY time';
Crumley answered 20/5, 2013 at 11:30 Comment(2)
"enterprise" may look good for golfing, but I wouldn't use it otherwise.Foulard
These are the voyages of the Perlship Enterprise, discovering new operators and new syntactations....Outsole

© 2022 - 2024 — McMap. All rights reserved.