Given a search string I need to select every record where (in the field the search is performed on) there is at least one word that begins with the given text.
For example:
'John Doe'
Have to be be selected with search strings like:
'joh'
'do'
'JOHN doe'
Have not to be selected with
'ohn'
'oe'
I need (possibly) to avoid full text search.
What I've found to work is
$query = 'SELECT * FROM MYTABLE WHERE SEARCHFIELD LIKE "' . $searchText . '%"'
. 'OR SEARCHFIELD LIKE "% ' . $searchText . '%"'
I'm asking if there is a better way to do that.
(for "better way" I mean better performance or same performance but more elegant)
Also, as the query will be built up with a prepared statement, how should I unescape LIKE metacharacters in the search string?
STRCMP() function in MySQL is used to compare two strings. If both of the strings are same then it returns 0, if the first argument is smaller than the second according to the defined order it returns -1 and it returns 1 when the second one is smaller the first one.
SQL pattern matching enables you to use _ to match any single character and % to match an arbitrary number of characters (including zero characters). In MySQL, SQL patterns are case-insensitive by default. Some examples are shown here. Do not use = or <> when you use SQL patterns.
To select first word in MySQL query, you can use SUBSTRING_INDEX().
LOCATE() function MySQL LOCATE() returns the position of the first occurrence of a string within a string. Both of these strings are passed as arguments. An optional argument may be used to specify from which position of the string (i.e. string to be searched) searching will start.
As already stated in the question the query
$query = 'SELECT * FROM MYTABLE WHERE SEARCHFIELD LIKE "' . $searchText . '%"'
. 'OR SEARCHFIELD LIKE "% ' . $searchText . '%"'
works for matching records where the SEARCHFIELD
contains a word that begins with (or is equal to) $searchText
Regarding performance I've made a test on my development machine MBP 2,2 GHz i7 quad core
:
Searching for a word on 4.000 records takes around 40 milliseconds.
Records are normally indexed (no fulltext).
I have few thousands records and the query doesn't run very often so for me is good.
The solution may not be suitable for other contexts.
To build a prepared statement with the above query I used the technique described here:
Escaping MySQL wild cards
The resulting code is as follows:
function like($s, $e)
{
return str_replace(array($e, '_', '%'), array($e . $e, $e . '_', $e . '%'), $s);
}
/* ... */
/* create a prepared statement */
$stmt = $mysqli->prepare(
'SELECT * FROM MYTABLE WHERE SEARCHFIELD LIKE ? ESCAPE "=" OR SEARCHFIELD LIKE ? ESCAPE "="'
);
if( $stmt )
{
/* escape the text */
$escSearchText = like( $searchText, "=" );
/* 'like' parameters */
$like1 = $escSearchText . "%";
$like2 = "%" . $escSearchText . "%";
/* bind parameters for markers */
$stmt->bind_param( "ss", $like1, $like2 );
/* ... */
Use this:
$query = "SELECT * FROM MyTable WHERE searchfield LIKE CONCAT('%', ?, '%')";
You don't need the OR
condition -- if a field matches search%
, it will also match %search%
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With