I am trying to create a search function where a user can input two words into a text field and it will split the words and construct a MySQL query.
This is what I have so far.
$search = mysql_real_escape_string( $_POST['text_field']);
$search = explode(" ", $search);
foreach($search as $word)
{
$where = "";
$where .= "product_code LIKE '%". $word ."%'";
$where .= "OR description LIKE '%". $word ."%'";
$query = "SELECT * FROM customers WHERE $where";
$result = mysql_query($query) or die();
if(mysql_num_rows($result))
{
while($row = mysql_fetch_assoc($result))
{
$customer['value'] = $row['id'];
$customer['label'] = "{$row['id']}, {$row['name']} {$row['age']}";
$matches[] = $customer;
}
}
else
{
$customer['value'] = "";
$customer['label'] = "No matches found.";
$matches[] = $customer;
}
}
$matches = array_slice($matches, 0, 5); //return only 5 results
It constructs and runs the query, but returns funny results.
Any help would be appreciated.
MySQL has something called LIMIT, so you last row would be needless.
Use Full-Text-Search for this: http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html - It's faster and more elegant
If your database is on MyISAM table format you could do a Fulltext search on the columns you are interested as Sn0opy mentioned already
Personally I believe that when it comes to mySQL if you actually want to create a great search engine use Sphinx (http://sphinxsearch.com/) or Solr (http://lucene.apache.org/solr/)
There may be a learning curve on both of them, but the results are professional.
Any chance of anything more specific than "funny results"? Off the cuff there are several possibilities but it really depends upon the results that are being returned. My PHP is a bit rusty so I will apologize up front if my brain throws in some java rules instead, but at first blush...
Name the array something other than $search. It probably isn't the problem, but it looks odd to have the array created by explode() carry the name of the string being exploded. Try something like $searched = explode(" ", $search); and then use $searched in the subsequent foreach() loop.
What if the user only puts in one search term? If there is no space in $text_field then explode will return an empty array, which should thoroughly jack up your query. You should at least verify that there is a space in $text_field before exploding $search. Likewise, what if the user enters two search terms, but one of the terms is two words separated by a space? Again you are going to get "funny results" because you will get results that you don't want along with duplicated results as the query extends itself to both of the words in a term individually.
Without knowing more of what you mean by "funny results" it is really difficult to trouble shoot this one.
Related
I'm trying to improve my MySQL query.
SELECT gamename
FROM giveaway
WHERE gamename LIKE '$query'
I got an input that consists of URL's that are formed like:
http://www.steamgifts.com/giveaway/l7Jlj/plain-sight
http://www.steamgifts.com/giveaway/okjzc/tex-murphy-martian-memorandum
http://www.steamgifts.com/giveaway/RqIqD/flyn
http://www.steamgifts.com/giveaway/FzJBC/penguins-arena-sednas-world
I take the game name from the URL and use this as input for a SQL query.
$query = "plain sight"
$query = "tex murphy martian memorandum"
$query = "flyn"
$query = "penguins arena sednas world"
Now in the database the matching name sometimes has more characters like : ' !, etc.
Example:
"Plain Sight"
"Tex Murphy: Martian Memorandum"
"Fly'N"
"Penguins Arena: Sedna's World!"
So when putting in the acquired name from the URL this doesn't produce results for the 2nd, 3rd and 4th example.
So what I did was use a % character.
$query = "plain%sight"
$query = "tex%murphy%martian%memorandum"
$query = "flyn"
$query = "penguins%arena%sednas%world"
This now gives result on the 1st and 2nd example.
.
On to my question:
My question is, how to better improve this so that also the 3rd and 4th ones work?
I'm thinking about adding extra % before and after each character:
$query = "%f%l%y%n%"
$query = "%p%e%n%g%u%i%n%s%a%r%e%n%a%s%e%d%n%a%s%w%o%r%l%d%"
But I'm not sure how that would go performance wise and if this is the best solution for it.
Is adding % a good solution?
Any other tips on how to make a good working query?
Progress:
After a bit of testing I found that adding lots of wildcards (%) is not a good idea. You will get returned unexpected results from the database, simply because you just added a lot of ways things could match.
Using the slug method seems to be the only option.
If i get your question well, you are creating a way of searching through those informations. And if that is the case then try
$query = addslashes($query);
SELECT name
FROM giveaway
WHERE gamename LIKE '%$query%'
Now if you want to enlarge your search and search for every single word that looks like the words in your string, then you can explode the text and search for each word by doing
<?php
$query = addslashes($query);
//We explode the query into a table
$tableau=explode(' ',$query);
$compter_tableau=count($tableau);
//We prepare the query
$req_search = "SELECT name FROM giveaway WHERE ";
//we add the percentage sign and the combine each query
for ($i = 0; $i < $compter_tableau; $i++)
{
$notremotchercher=$tableau["$i"];
if($i==$compter_tableau) { $liaison="AND"; } else { $liaison=""; }
if($i!=0) { $debutliaison="AND"; } else { $debutliaison=""; }
$req_search .= "$debutliaison gamename LIKE '%$notremotchercher%' $liaison ";
}
//Now you lauch your query here
$selection=mysqli_query($link, "$req_search") or die(mysqli_error($link));
?>
By so doing you would have added the % to every word in your query which will give you more result that you can choose from.
I have a filter in my mvc model which takes a variable from a search field. It searches titles, among other things, but the search results are poor. This may be a simple syntax problem, but I couldn't see it searching.
I have some item titles like:
"Manolo Blahnik Carolyne Gold Glitter Slingback Pump (35.5, Gold)"
or
"Belstaff Trialmaster Jacket"
Currently if you search for "manolo blahnik shoes" or "belstaff jacket" you get no results.How do I get matching on ANY of the words from any part of the string?
I have tried adding % to either side of the variable like this %'.$keyword.'% but that doesn't work.
//Filtering search field
$jinput = JFactory::getApplication()->input;
$keyword = $jinput->get('keyword', '', 'NULL');
if($keyword!=''){
$keyword = $db->Quote('%' . $db->escape($keyword, true) . '%');
$query->where('( a.title LIKE '.$keyword.' OR a.features LIKE '.$keyword.' OR a.brand LIKE '.$keyword.' )');
}
i think your best bet would be then to explode the search sting you get and create OR's from them
so
$keyword = "manolo blahnik shoes";
$keyWords = explode(' ', $keyword);
$ors = array();
foreach($keywords as $word) {
$word = $db->Quote('%' . $db->escape($word, true) . '%');
$ors[] = "a.title LIKE %word";
$ors[] = "a.features LIKE $word";
$ors[] = "a.title brand LIKE $word"
}
$queryString = implode(' OR ', $ors');
$query->where($queryString);
Since just one of the words should be in just one of the 3 columns you can have a whole string of OR's.
Of course this can become a rather large query so maybe that is something you would have to keep in mind.
Also this code is an example that you can change to your needs for example make sure that $keywords is not empty before you explode ,escape the keywords that you get or use a prepared statement to prevent sql injection things like that.
For something like this it might even be wise to look into solr for your search instead of doing it directly with mysql. Or if you have a myisam table you might look into FULL TEXT search mysql FULLTEXT search multiple words
i have an array of strings and i need to search whether the strings of the array exits in database or not. i am using following query:
foreach($array as $s)
{
if(preg_match('/^(\bpho)\w+\b$/', $s))
{
$query="select * from dictionary where words REGEXP '^".$s."$'";
$result=$db->query($query) or die($db->error);
if($result)
{
$count += $result->num_rows;
}
}
}
but this query taking long time to execute. PLease provide a solution to reduce the searching time
I don't think your problem here is about your code. I think you should optimize your database.
I'm not very good at it but I think you could add indexes in your database to speed up the research
Combine all the search strings into a single regular expression using alternation.
$searches = array();
foreach ($array as $s) {
if (preg_match('/^(\bpho)\w+\b$/', $s)) {
$searches[] = "($s)";
}
}
$regexp = '^(' . implode('|', $searches) . ')$';
$query="select 1 from dictionary where words REGEXP '$regexp'";
$result=$db->query($query) or die($db->error);
$count = $result->num_rows;
If $array doesn't contain regular expressions, you don't need to use the SQL REGEXP operator. You can use IN:
$searches = array();
foreach ($array as $s) {
if (preg_match('/^(\bpho)\w+\b$/', $s)) {
$searches[] = "'$s'";
}
}
$in_list = implode(',', $searches);
$query="select 1 from dictionary where words IN ($in_list)";
$result=$db->query($query) or die($db->error);
$count = $result->num_rows;
Searching the whole database is a large job, I think a better way is you can cache some parts of the database, and than search in the cache. Redis is very good.
Modify your query so that is doesn't select all table columns - that is a waste of resources. Instead, just let the database count the number of rows containing the search query and return back only a single answer (matches):
$query = "SELECT COUNT(id) AS matches FROM dictionary WHERE words REGEXP '^".$s."$'";
How are you indexing your database? If your words column is not indexed properly, then your regexp would take a long time. Examine your database structure and potentially add indexing to the words column.
P.S. And don't forget to fetch the matches column instead of using num_rows
i've got a basic search code to search through database when people search for more than 1 word. i've done loads of research and all the algortihms seem to be prety much the same. trim the search words. explode them into an array. then use either foreach or while to add each word of array onto the msql_query.
but there is a problem. here is my code:
if (isset($_POST['search'])){
$words = $_POST['searchfield'];
$arraySearch = explode(" ", trim($words));
$countSearch = count($arraySearch);
$a = 0;
$query = "SELECT * FROM parts WHERE ";
while ($a < $countSearch)
{
$query = $query."description RLIKE '$arraySearch[$a]'";
$a++;
if ($a < $countSearch)
{
$query = $query." AND ";
}
}
$results=mysql_query($query) or die($query);
if(!$results){
$msg = "No results, please try another search";}
}
ok so look at the second $query variable where it says "decription RLIKE '$arraySearch'"
For the search to work whatever word is in $arraySearch HAS to be in single quotes. BUT when i try it the script will just not run.
BUT if i take away the single quotes the script runs. but it doesn't perform the search. it dies and comes up with error. in this case i've made the error message the actual query to try and find out what's going wrong.
so if i take away the single quotes and search for "car tyre". the query will be SELECT * FROM parts WHERE description RLIKE car AND description RLIKE tyre but it won't work unless its like this: SELECT * FROM parts WHERE description RLIKE 'car' AND description RLIKE 'tyre'.
i know this because i have tested the earch by just typing it into another query to test it.
i've spent hours and hours trying to figure a way round this but i can't figure it out. why is it doing this to me? how do i get round it? and why doesn't anyone else seem to be having the same problem?????
thanx for help :)
.... added as afterthough:
i'm thinking that the only possible way of doing this is to have the single quotes already inside the variable. but i don't know how to do that. as in:
$arraySearch = ("'car'", "'tyre'"); any ideas?
To get the quotes to work correctly, try to write it like this:
$query = $query."description RLIKE '".$arraySearch[$a]."'";
Adding the ". and ." inside of the single quotes may solve your problem.
Try doing this:
$quote = "'";
$query = $query."description RLIKE $quote$arraySearch[$a]$quote";
Right now I'm just using a simple
WHERE name LIKE '%$ser%'
But I'm running into an issue - say the search is Testing 123 and the "name" is Testing, it's not coming back with any results. Know any way to fix it? Am I doing something wrong?
If you want to search for 'Testing' or '123' use OR:
WHERE (name LIKE '%Testing%' OR name LIKE '%123%')
Note however that this will be very slow as no index can be used and it may return some results you didn't want (like "4123"). Depending on your needs, using a full text search or an external database indexing product like Lucene might be a better option.
That's how LIKE works - it returns rows that completely contain the search string, and, if you use "%" optionally contain something else.
If you want to see if the field is contained in a string, you can do it this way:
SELECT * FROM `Table` WHERE "Testing 123" LIKE CONCAT("%",`name`,"%")
As Scott mentioned, you cannot check to see if the search contains the column value, it works the other way round.
so if $ser = "testing" and table has a row name = testing 123 it will return
For what you're trying to do you'll need to tokenize the search query into terms and perform an OR search with each of them or better still check out mysql full text search for a much better approach
After the variable $ser is replaced, the query is:
WHERE name LIKE '%Testing 123%'
You should build the query separating by words:
WHERE name LIKE '%$word[1]%$word[2]%'
not efficient (as your example) but working as you want:
WHERE name LIKE '%$ser%' OR '$ser' LIKE CONCAT('%', name, '%')
As mentioned by Mark and others, a full text search method may be better if possible.
However, you can split the search string on word boundary and use OR logic—but check for the whole string first, then offer the option to widen the search:
NOTE: Input sanitization and preparation not shown.
1. Query with:
$sql_where = "WHERE name LIKE '%$ser%'";
2. If zero results are returned, ask user if they would like to query each word individually.
3. If user requests an 'each word' search, query with:
$sql_where = get_sql_where($ser);
(Working) Example Code Below:
$ser = 'Testing 123';
$msg = '';
function get_sql_where($ser){
global $msg;
$sql_where = '';
$sql_where_or = '';
$ser = preg_replace("/[[:blank:]]+/"," ", trim($ser)); //replace consecutive spaces with single space
$search_words = explode(" ", $ser);
if($search_words[0] == ''){
$msg = 'Search quested was blank.';
}else{
$msg = 'Search results for any of the following words:' . implode(', ', $search_words);
$sql_where = "WHERE name LIKE '%$ser%'";
foreach($search_words as $word){
$sql_where_or .= " OR name LIKE '%$word%'";
}
}
return $sql_where . $sql_where_or;
}
$sql_where = get_sql_where($ser);
//Run query using $sql_where string