Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

more elegant way to construct SQL adding WHERE and using placeholders

Tags:

perl

dbi

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';
like image 625
xoid Avatar asked May 20 '13 07:05

xoid


People also ask

What is the use of placeholder in SQL?

A placeholder expression provides a location in a SQL statement for which a third-generation language bind variable will provide a value. You can specify the placeholder expression with an optional indicator variable.

What are bindings in SQL?

Bind parameters—also called dynamic parameters or bind variables—are an alternative way to pass data to the database. Instead of putting the values directly into the SQL statement, you just use a placeholder like ? , :name or @name and provide the actual values using a separate API call.

Which character is used as placeholders in Preparedstatement?

With MySQLdb, you should use a placeholder of %s to format all data values as strings. MySQL will perform type conversion as necessary. If you want to place a literal % character into the query, use %% in the query string.


2 Answers

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
);
like image 135
friedo Avatar answered Sep 18 '22 18:09

friedo


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';
like image 30
mpapec Avatar answered Sep 21 '22 18:09

mpapec