elam has asked for the wisdom of the Perl Monks concerning the following question:

Howdy all,

I'm writing an application to scour a client's database using perl and dbi. I would like to have just one screen, with multiple input boxes. The problem with this is the number of permutations of sql queries I would have to craft. One table has 5 fields which would require 31 different queries to ensure all possible variations of input data are captured.

My other option is to force the user to begin with a specified input and filter down from there. Am I missing something obvious or are these the only 2 ways to do this? I would really like to do the first option but don't have the time to plug bunches of queries. Do many ifelse statements bog perl down?

Thanks,
Elam

Replies are listed 'Best First'.
Re: Database queries w/lots of inputs.
by dws (Chancellor) on May 13, 2003 at 20:07 UTC
    The problem with this is the number of permutations of sql queries I would have to craft.

    Assuming that you're doing some sort of query-by-example (QBE) form, where the WHERE clause you're generating depends on which form fields have non-empty cells, you can do build a query on-the-fly and use bind parameters by doing something like the following:

    As you're scanning your form fields, build an array that holds records (anonymous arrays) of the form   (field, relop, value) where relop defaults to '='. (This scheme allows you to specify things like "> 47".)

    You can then scan this array to build the WHERE clause. You have two options here. You could translate directly to   field relop value and then join() these fragments with an AND, or you could translate to   field relop ? (being careful to correctly quote the values) before joining with an AND. Then, prepare() the query. In the later case, you need to scan your array a second time to extract an array of values to pass to execute().

    If your application can benefit from caching queries, you can use a concatenation of field names as a key to retrieve a previously-prepared query. E.g., after you construct and prepare a query, save the statement handle using the fields in the WHERE clause as a key.

    This scheme can be adjusted to accomodate both IS [NOT] NULL (by decorating the field name as used in the key) and BETWEEN clauses (by repeating the field name).

Re: Database queries w/lots of inputs.
by shemp (Deacon) on May 13, 2003 at 20:02 UTC
    Are your searchable fields just matching for exact values, or are you looking for ranges, contains, etc. In any case, here is a simple way to do it if you're only looking for exact matches for each field.
    ... my $form = CGI->new(); my $db_handle = DBI->connect(...); my @fields = qw(f_1 f_2 f_3 f_4 f_5); my @query_parts; foreach my $field (@fields) { if ( defined $form->param($field) ) { push @query_parts, "$field = " . $db_handle->quote($form->para +m($field)); } } if ( ! scalar(@query_parts) ) { # do something else return; } my $query = "SELECT * FROM Table_Name WHERE "; $query .= join " AND ", map { "( $_ )" } @query_parts;
    I use schemes like this, with a lot of additions in a number of production systems. This specific code is untested, but the idea is solid.
Re: Database queries w/lots of inputs.
by bigj (Monk) on May 14, 2003 at 10:23 UTC
    Assuming you are talking about "Query by Example" another standard way, that has the main advantage of being very readable and easy to maintain is quite the following. But it only works good, if it is also O.K. to work with the LIKE statement:
    # I assume the database handler $dbh is already initialized my $sth = $dbh->prepare(" SELECT * FROM table WHERE field1 LIKE ? AND field2 LIKE ? AND field3 LIKE ? AND field4 LIKE ? AND field5 LIKE ? "); for ($field1, $field2, $field3, $field4, $field5) { $_ = "" unless defined $_; $_ .= "%"; } $dbh->execute($field1, $field2, $field3, $field4, $field5); # But please choose better names than $fieldX :-)

    Greetings,
    Janek