I am using a HTML form to allow users to find entries in a database table:
<form action="controller.php" method="get">
<input type="text" name="word" id="word">
The table in my database has a column called keywords that contains multiple values, and so I use a SELECT query to select all rows that have any keywords that match what the user typed into the form. So controller.php contains this query:
$word= $_GET['word'];
$query = SELECT * FROM table WHERE table.keywords LIKE '%{$word}%
This works fine, except if a user types more than one word into the search box. How do I alter this such that, when a user types more then one word into the search box, it will return all rows that have either of the users words in its keywords column.
i.e, user searches "apples oranges", and the query returns all rows that have either "apples" or "oranges" in their keywords field.
You can try with -
$words = explode(' ', $word);
$query = "SELECT * FROM table WHERE table.keywords IN (".implode(',', $words).")";
Or -
$query = "SELECT * FROM table WHERE";
$conds = array();
foreach ($words as $val) {
$conds[] = "table.keywords LIKE '%".$val."%'";
}
$query .= implode(' OR ', $conds);
The checks can be added if required.
You could use a regular expression:
$words = explode(' ', $_GET['word']);
$regex = implode('|', $words);
$query = "SELECT * FROM table WHERE table.keywords REGEXP '{$regex}'";
I use this code and work fine
$regcond = trim($_GET['word']);
$regcond = preg_replace('!\s+!', ' ', $regcond); //change how many space beetwen word to one space
$regcond = trim($regcond);
$regcond = str_replace(" ",".+",$regcond); // change all space to .+ for search with regex
$final_cond = 'SELECT * FROM table WHERE table.keywords REGEXP "' . $regcond . '"';
$words = explode(" ",$string);
$string = array_map(function(&$word){
return "+".$word."*";
},$words);
$term = implode(" ",$string);
$query = "SELECT * FROM table_name WHERE MATCH(column_name) AGAINST('{$term}' IN BOOLEAN MODE)";
LIKE command is good for one-word string. For advanced searching in database use FULLTEXT search.
https://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html
As in SQL unable to search for single name try splitting the name based on spaces like i.e Heavens Road and appending to string i.e ('%Heavens%') OR (%Road%) in final query.
SELECT id, gps, street_name
FROM streets
WHERE street_name LIKE ('%Heavens%') OR (%Road%)
e.g if more terms are then LIKE (%1term%) OR (%2term%) OR (%3term%) OR (%4term%)
Here's my PHP solution where the search string contains multiple keywords, can be in any order, may be separated by multiple spaces, may have repetitions, must be ranked on how many keywords found, and is sql injection safe. Assume table is called Topics with an ID of TopicID, text in column TopicText and keywords in column Keywords, and your mySQL connection is $dbConn
//convert search string to lowercase - will do case insensitive search later
$words = trim(strtolower($_GET['k']));
//remove punctuation and wildcards
$words = str_replace(array('*', '?', '-', '.', '/', '(', ')', '+', '&'), '', $words);
//turn the string into an array of unique words
$words = array_unique(explode(' ', $words));
//strip the words we are not interested in
$stopWords = array('', '*', '?', 'a', 'about', 'an', 'and','are', 'as', 'at', 'be', 'by', 'for', 'from', 'how', 'in', 'is', 'it', 'of', 'on', 'or', 'that', 'the', 'this', 'to', 'was', 'what', 'when', 'where', 'who', 'will', 'with');
foreach($stopWords as $word) {
if (($key = array_search($word, $words)) !== false) unset($words[$key]);
}
//build SQL statement
$sql = "select TopicText, Score from (select TopicID, 0";
foreach($words as $word) {
if($word>'') $sql .= "+if(Keywords regexp '" . $dbConn->real_escape_string($word) . "',1,0)";
}
$sql .= " as Score from Topics) T join Topics TT on TT.TopicID = T.TopicID where T.Score>0 order by Score desc";
If you don't have a column with keywords, one could use the TopicText column as the regexp target above.
regular expression does it for me.
$str = $_GET['words'];
$commonwords = 'a,an,and,I,it,is,do,does,for,from,go,how,the,this,are';// you dont want to search for these common words
$commonwords = explode(",", $commonwords);
$str = explode(" ", $str);
foreach($str as $value){
if(!in_array($value, $commonwords)){ // remove the common words from search
$query[] = $value;
}
}
$query = implode(" ", $query);// generate coma separated values
$str2 =(explode(" ",$query));// convert the values to an array
$Words = implode('|',array_values($str2)).'';// generate values to be searched and make regex
"SELECT * FROM table_name WHERE `keywords` REGEXP '$Words'"
Works for me where the user search for more than one product each separated by a space. user does not have to type full words
$word= $_GET['word'];
if (strpos($word, ' ') !== FALSE) {
$wordArr = explode(' ', $word);
$where = '';
foreach ($wordArr AS $word) {
$where .= " table.keywords LIKE '%{$word}%' OR";
}
$where = trim($where, 'OR');
} else {
$where = "table.keywords LIKE '%{$word}%' ";
}
$query = "SELECT * FROM table WHERE $where";
echo $query;
Related
I have a current SQL search query that lets users enter keywords to search for my SQL database. At the moment, the search will work with multiple words, but will show all results for either keyword. If you type in "Ford Mustang" it will show all results that have either "Ford" or "Mustang", but I need it to only show results that show both "Ford" and "Mustang".
What I have tried is below
public function getProductByName($name){
$stmt = $this->pdo->prepare('SELECT * FROM tbl_products WHERE name REGEXP :names');
$names = "[[:<:]](" . str_replace(" ", "|", $name) . ")[[:>:]]";
$stmt->execute(array('names' => $names));
return $stmt;
}
maybe this what you're looking for
select * from example where name like "%mustang%ford%"
You can write the query
select * from tbl_products where name like "%Mustang%" and name like "%ford%";
PHP code
//you may split search string like
$searchArray = explode(' ', $name);
//for loop for preparing the query
$query = 'SELECT * FROM tbl_products WHERE ';
$searchParams = array();
$conditions = [];
for($searchArray as $searchStr){
$conditions[] = 'name like ?';
$searchParams[] = "%$searchStr%";
}
//attach the conditions
$query .= implode(" and ", $conditions);
//execute the query
$stmt = $this->pdo->prepare($query);
$stmt->execute($searchParams);
I am wondering how I can properly check keywords with SQL "LIKE";
I have a script which looks like that:
$search_keywords = $_POST['search-keywords'];
$search_keywords = str_replace(" ","%", $search_keywords);
$search_keywords = '%' . $search_keywords . '%';
$search = $odb -> query("SELECT * FROM `cars` WHERE `keywords` LIKE '".$search_keywords."' ORDER BY `id` ASC");
$rows = $search->rowCount();
if ($rows > 0) {//Loop}
In fact, it's working but only when keywords in the database look like that:
audi, a3, silver and I search for audi a3
If i am trying to search like that: a3 audi it's not working
Any hints?
You need to split $search_keywords into separate words, and search for each of them.
To search for an item in a comma-separated list, use FIND_IN_SET() rather than LIKE. LIKE '%audi%' will also match audi-quatro.
$keyword_array = explode(" ", $_POST['search_keywords']);
foreach ($keyword_array as &$keyword) {
$keyword = "FIND_IN_SET('$keyword', keywords)";
}
$tests = implode(' AND ', $keyword_array);
// $tests contains something like: FIND_IN_SET('a3', keywords) AND FIND_IN_SET('audi', keywords)
$sql = "SELECT * FROM `cars` WHERE $tests ORDER BY `id` ASC";
$search = $odb->query($sql);
It's a best practice to use PDO::prepare when you are passing user data in your request, to evoid SQL Injection
$search = $odb->prepare("SELECT * FROM cars WHERE keywords
LIKE CONCAT('%',:keyword,'%')
ORDER BY id ASC");
$results = $search->execute([":keywork" => $search_keywords]);
My database has row with a column like
data1+data2+data3+data4
How can i search specific value by sql query in php?
For example data2?
The +s separate each data point.
Why don't you try something like below:
SELECT (data1+data2+data3+data4) AS total
FROM Table
WHERE total LIKE '%YOUR_QUERY%'
Now you can use the index total
$lcSearchVal = "data1+data2+data3+data4";
$lcSearchVal = explode( '+', $lcSearchVal );
$sql = 'SELECT * FROM tablename WHERE (';
$data_array = array();
foreach( $lcSearchVal as $lcSearchWord )
{
$data_array[] = 'fieldname LIKE "%'.$lcSearchWord.'%"';
}
$sql .= implode(' OR ', $data_array).')';
print $sql;
I have a PHP array containing values and I want to query the database to find any results where the ItemName contains any of the values in the array.
$current_item = 'Big Fancy Red Car';
$words = explode(' ',$current_item); // Array of words to search
And the query:
SELECT ID FROM store_accessories WHERE ItemName LIKE '%$words%'
How do I select the ID of any items in the table whose ItemName contains any of the values in the $words array?
You can do it like this:
First explode the value into an array:
$terms = explode(' ', $search_term);
Loop the array to add the LIKE
foreach ($terms as $term) {
$term = mysql_real_escape_string($term);
$likes[] = "field LIKE '%$term%'";
}
Add to the query:
$sql = "select * from table where";
$sql .= implode(' OR ', $likes);
You can get the LIKE like this directly, also substituting ' with '' and escaping _ and %:
$field = "ItemName";
$like = "$field LIKE '%".str_replace(
array("'" , "_" , "%" , " " ),
array("''", "\\_", "\\%", "%' OR $field LIKE '%"),
$currentItem)."%'";
I am having some trouble displaying text from database using PHP and SQL. Below is a script similar to what I have.
$search_split = explode(" ", $search); //$search is what user entered
foreach ($search_split as $searcharray) {
$searched = mysqli_query($connect, "SELECT * FROM people WHERE `description` LIKE '%$searcharray%'");
while($info = mysqli_fetch_array($searched)) {
echo $info['description'];
}
}
So, for example the user enter 'He is male'. I split the word into three part 'He', 'is' and 'male' using 'explode' function. After that, I search the database for words that is similar to those three word. However, if a row have all the three words, it would display the row three times. How can I make it to display only once?
You could do something like this:
$search = 'test search me';
$search_split = array_map(function($piece) use ($mysqli_connection){
return "'%" . $mysqli_connection->real_escape_string($piece) . "%'";
}, explode(' ', $search)); //$search is what user entered
$search_split = implode(' OR `description` LIKE ', $search_split);
$sql = "SELECT * FROM people WHERE `description` LIKE $search_split";
echo $sql; // SELECT * FROM people WHERE `description` LIKE '%test%' OR `description` LIKE '%search%' OR `description` LIKE '%me%'
$searched = mysqli_query($connect, $sql);
Can you use full text search?
Add a full text index to the table
ALTER TABLE people ADD FULLTEXT(description);
Then you can use a query like this
SELECT *
FROM people
WHERE
MATCH ( description )
AGAINST ('+He +is +male' IN BOOLEAN MODE)
First store your results into one array then display it. Refer below code.
$search_split = explode(" ", $search); //$search is what user entered
foreach ($search_split as $searcharray) {
$searched = mysqli_query($connect, "SELECT * FROM people WHERE `description` LIKE '%$searcharray%'");
while($info = mysqli_fetch_array($searched)) {
$results[$info['YOUR_PRIMARY_KEY']] = $info['description']; // this will over write your previous record
}
}
foreach($results as $result){
echo $result;
}
Now every records display only once.
You have put your db query in a foreach loop, which loops 3 times (with the current data: he, is and male). What you want to do is put all the search variables in one query, something like:
$search_split = explode(" ", $search); //$search is what user entered
$querypart = "'%" . implode("%' AND '%", $search_split) . "%'"; // use OR or AND, to your liking
$searched = mysqli_query($connect, "SELECT * FROM people WHERE `description` LIKE " . $querypart);
while($info = mysqli_fetch_array($searched)) {
echo $info['description'];
}
This does not take any escaping/sanitizing of the query input, be aware...
$result = array();
$search_split = explode(" ", $search); //$search is what user entered
foreach ($search_split as $searcharray) {
$searched = mysqli_query($connect, "SELECT * FROM people WHERE `description` LIKE '%$searcharray%'");
while($info = mysqli_fetch_array($searched)) {
$result[] = $info['description'];
}
}
$finalres = array_unique($result);
so, finalres contains unique results
for($i = 0; $i < count($finalres); $i++)
echo $finalres[$i];