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';
1
  • SQL::Maker would abstract away the SQL details. Commented May 20, 2013 at 8:14

3 Answers 3

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
);
Sign up to request clarification or add additional context in comments.

1 Comment

DBIx::Class uses SQL::Abstract under the hood. $schema->resultset('Calls')->search({ time => {-between, [$from, $until]}, defined $phone ? (phone => $phone) : () }, { order_by => {-asc => 'time'} } )->all
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';

Comments

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';

2 Comments

"enterprise" may look good for golfing, but I wouldn't use it otherwise.
These are the voyages of the Perlship Enterprise, discovering new operators and new syntactations....

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.