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

What is the best way to construct a LIKE search with DBI? I know that I should always use $dbi->quote or a placeholder to keep the search string from messing up my SQL statement (the search string will be entered by a user on a webpage), and I have read that using a placeholder in this case can cause performance problems. However, using $dbi->quote on a search string like "%foo%" (where "foo" is the string entered by the user on the webpage and %'s are added by the program) will quote out the %'s. I also can't just put %'s on the outsides of the quoted string, because the quote function adds in quotes, so that would give me "%'foo'%". In the past, I've used $dbi->quote on the search string without the %'s, then used a regex to add a % after the first ' and before the last ' in the string. Certainly there's a better way!

Thanks,

Curtis H.

Replies are listed 'Best First'.
Re: DBI, quoting, and LIKE searches (no good answer)
by tye (Sage) on Dec 26, 2002 at 17:33 UTC

    There may not be a fully portable answer to this. My best guess for a concise answer would be:     "... LIKE '%" . quotemeta($str) . "%' ..." but I fear that some database won't handle all of the potential backslashes. So a more conservative approach might be called for:

    my $pattern= $string_from_user; $pattern =~ s#(['%_\[\]])#\\$1#g; "... LIKE '%$pattern%' ..."
    but then some databases might support things other than %, _, and [chars] in their LIKE constructs so the first answer might be better.

    Do all databases even support \ for escaping LIKE "wildcards"? What about for escaping single quotes (apostrophes)? I believe that using two consecutive apostrophes to represent a single apostrophe when inside of an apostrophe-delimited string is part of the SQL standard. So 'don''t' = "don't" in SQL. I've long been curious what the standard says about LIKE strings but have always ended up looking up what my current database supports instead (which has always been the use of \ to escape things).

    In dealing with MySQL for PerlMonks, I found what I consider to be a quirk. If I want to find all strings containing a backslash followed by a percent sign (\%), I have to tell MySQL     LIKE '%\\\\\%%' (which means I'd have to tell Perl "... LIKE '%\\\\\\\\\\%%' ...") because, when I use what I would have expected to work (LIKE '%\\\%%'), it appears that some backslahses are consumed when MySQL parses the single-quoted string and the LIKE operation ends up seeing %\\%%, which finds strings that contain just a backslash.

    So you might have to resort to:

    # Escape "wildcard" characters in user input: my $pattern= quotemeta($string_from_user); # Escape things processed by 'single quote' parsing: $pattern =~ s#([\\'])#\\$1#g; "... LIKE '%$pattern%' ..."
    So I fear you'll have to test and use what works for your current database. This should probably be abstracted by DBI but I don't believe that it currently is.

            - tye
Re: DBI, quoting, and LIKE searches
by pfaut (Priest) on Dec 26, 2002 at 17:06 UTC

    Try something like this for your select and bind the user entered string to the parameter

    Select * from mytable where myfield like '%' || ? || '%'
    --- print map { my ($m)=1<<hex($_)&11?' ':''; $m.=substr('AHJPacehklnorstu',hex($_),1) } split //,'2fde0abe76c36c914586c';
      Aha! It works. But, will this have the performance problems associated with using place holders and saying $sth->execute->("foo%")? It mentioned here that it didn't use the Index like it should. I'm not a database expert, so I don't know how to test this.

        Since these LIKE strings start with a '%', the database can't use an index at all. So that should not be a concern here.

                - tye
Re: DBI, quoting, and LIKE searches
by dws (Chancellor) on Dec 26, 2002 at 19:52 UTC
    What is the best way to construct a LIKE search with DBI?

    There's a discussion of binding and LIKE clauses in A DBI Query Binding Pitfall. The upshot is that RDBMS query optimizers will assume the worst if they see a LIKE clause but don't have a string to examine to see if index use is possible. There are workarounds.

Re: DBI, quoting, and LIKE searches
by Three (Pilgrim) on Dec 27, 2002 at 14:18 UTC

    This is sort of off topic but I think it should be said.

    Like is good for searches, but I prefer to use soundex for searches..
    The great thing about soundex is that it gets words that sound alike not just spelled alike.

    This works really good in Oracle 9i where you can index soundex for speed.

    Here is a example.

    select * from demographics where soundex(name) = soundex(?)