views:

2500

answers:

5

I'm working on an 'advanced search' page on a site where you would enter a keyword such as 'I like apples' and it can search the databse using the following options:

Find : With all the words, With the exact phrase , With at least one of the words, Without the words

I can take care of the 'Exact phrase' by:

SELECT * FROM myTable WHERE field='$keyword';

'At least one of the words' by:

SELECT * FROM myTable WHERE field LIKE '%$keyword%';//Let me know if this is the wrong approach

But its the 'With at least one of the words' and 'Without the words' that I'm stuck on.

Any suggestions on how to implement these two?

Edit: Regarding 'At least one word' it wouldn't be a good approach to use explode() to break the keywords into words, and run a loop to add

(field='$keywords') OR ($field='$keywords) (OR)....

Because there are some other AND/OR clauses in the query also and I'm not aware of the maximum number of clauses there can be.

+2  A: 

You could use

With at least one of the words

SELECT * FROM myTable WHERE field LIKE '%$keyword%' 
or field LIKE '%$keyword2%' 
or field LIKE '%$keyword3%';

Without the word

SELECT * FROM myTable WHERE field NOT LIKE '%$keyword%';
Re0sless
Please see my edit above. Do you think this is a good solution, i.e is there any limit to the number of OR clauses that can be put in a query?
Click Upvote
There probably is a limit, but i have never hit it and have done much longer where statements, but the more you add the slower the query will be and `like` is particularly slow.
Re0sless
There's no practical limit. If you have other WHERE clauses then bracket your keyword search: " WHERE something = x AND (field LIKE ... OR field LIKE ... OR ...)
Greg
+2  A: 

I'm not sure you could easily do those search options in a naive manner as the other two.

It would be worth your while implementing a better search engine if you need to support those scenarios. A simple one that could probably get you by is something along these lines:

When an item is added to the database, it is split up into the individual words. At this point "common" words (the, a, etc...) are removed (probably based on a common_words table). The remaining words are added to a words table if they are not already present. There is then a link made between the word entry and the item entry.

When searching, it is then a case of getting the word ids from the word table and the appropriate lookup of item ids in the joining table.

Giraffe
+10  A: 

I would suggest the use of MySQL FullText Search using this with the Boolean Full-Text Searches functionality you should be able to get your desired result.

Edit:

Requested example based on your requested conditions ("Its just one field and they can pick either of the 4 options (i.e 1 word, exact words, at least 1 word, without the term).")

I am assuming you are using php based on your initial post

<?php
$choice = $_POST['choice'];
$query = $_POST['query'];

if ($choice == "oneWord") {
    //Not 100% sure what you mean by one word but this is the simplest form
    //This assumes $query = a single word
    $result = mysql_query("SELECT * FROM table WHERE MATCH (field) AGAINST ('{$query}' IN BOOLEAN MODE)");
} elseif ($choice == "exactWords") {
    $result = mysql_query("SELECT * FROM table WHERE MATCH (field) AGAINST ('\"{$query}\"' IN BOOLEAN MODE)");
} elseif ($choice == "atLeastOneWord") {
    //The default with no operators if given multiple words will return rows that contains at least one of the words
    $result = mysql_query("SELECT * FROM table WHERE MATCH (field) AGAINST ('{$query}' IN BOOLEAN MODE)");
} elseif ($choice == "withoutTheTerm") {
    $result = mysql_query("SELECT * FROM table WHERE MATCH (field) AGAINST ('-{$query}' IN BOOLEAN MODE)");
}
?>

hope this helps for full use of the operators in boolean matches see Boolean Full-Text Searches

Mark Davidson
+1, this is the best answer, but I'd also detail that fulltext on mysql is only available for myisam tables, not innodb ones. So you choose between transactional consistency or search.
Adriano Varoli Piazza
If you give some source code which shows how the two features (i.e all words and without the words) can be done with Full text I might accept your answer.
Click Upvote
I would be happy to provide you with some sample code. If you can tell me are there two separate fields in your search form for with and without or are you using one field?If it's one field you can simply allow the user to append the words the want to exclude with a -.
Mark Davidson
Its just one field and they can pick either of the 4 options (i.e 1 word, exact words, at least 1 word, without the term).
Click Upvote
Ok I will post up some example code based on that every shortly.
Mark Davidson
+1, great answer!
Shoaibi
+1  A: 

Search is notoriously difficult to do well.

You should Consider using a third party search engine using something like Lucene or Sphider.

seanyboy
A: 

Giraffe and Re0sless pooseted 2 good answers.

notes: "SELECT * " sucks... only select the columns that you need. Re0sless puts a "OR" between keywords. - you should eliminate common words (" ","i","am","and"..etc) - mysql has a 8kb i belive limit on the size of the query, so for really long SELECTS you should slipt it into separate queries. - try to eliminate duplicate keywords (if i search for "you know you like it" the SELECT should basically only search for "you" once and elimnate common words as "it")

Also try to use "LIKE" and "MATCH LIKE" (see mysql man page) it could do wonders for "fuzzy" searches

Quamis