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]);
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);
My database looks like this:
I have a variable that looks like this:
$following = "John, Sarah";
I would like to get the rows where the column 'username' is in the variable $following (in this case, John and Sarah). To do this, I had a look at the answer https://stackoverflow.com/a/1356018/5798798 which suggested I use IN in my query, which I have attempted:
$following = "John, Sarah";
$stmt = $con->prepare("SELECT * FROM events WHERE username IN ('$following')");
$stmt->execute();
while($row = $stmt->fetch()) {
echo $row['eventtype'];
}
The problem is that the query is returning no data. My desired result would be:
spoke walked
From what I suggested in comments to use the following:
$following = "John, Sarah";
$following = explode(", ", $following);
$string = implode(", ", $following);
It ended up that I didn't include the quotes for the implode()'ing.
The final solution was to add the single quotes in the first parameter for the implode() function:
$following = implode("','",$following);
$following = join("', '", $following);
join no more returns an array. It is a string now.
You can use like this:
$in = str_repeat('?,', count($following ) - 1) . '?';
$stmt = $con->prepare("SELECT * FROM events WHERE username IN ($in)");
$stm->execute($following);
with out using join you directly implode array by the following way
$stmt = $con->prepare('SELECT * FROM events WHERE username IN ("'. implode('","', $following).'")');
$stmt->execute();
while($row = $stmt->fetch()) {
echo $row['eventtype'];
}
Note: $following always should be in array
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'm getting trouble to add the search in my site. I cannot figure out the way to make it done.
I 've a table as follow:
TABLE A
id text
1 Hello there whats up. I'm trying to code.
2 there need to be this code
Now I want search using the
Keywords = hello code
And the results should provide me both the rows because both the rows contains some portion of the keyword as follow:
id text
1 **Hello** there whats up. I'm trying to **code**
2 there need to be this **code**
Also the result should provide the row with max number of keywords matched first.
I tried doing this but it only provide me some of my desire results.
<?php
$keyword = 'hello code';
$exloded = explode(' ', $keyword);
foreach($exploded as value):
$sth = $db->query("SELECT * FROM A WHERE `text` LIKE :value");
$sth->execute(array(':value' => '%'.$value.'%'));
$rows = $sth->fetchAll();
endforeach;
echo $rows;
?>
Updated
I simply Did this and it worked fine for me. But I want to know whether this is the correct way to get the work done.
$keyword = hello code;
$query ="SELECT *, MATCH(`page_content`) AGAINST('$keyword' IN BOOLEAN MODE) AS score FROM super_pages WHERE MATCH(`page_content`) AGAINST('$keyword' IN BOOLEAN MODE) ORDER BY score DESC";
$sth = $this->db->query($query);
$result = $sth->fetchAll();
$rows will have the data where your keyword code matches in your table you can rewrite your code to match for both keywords as
$keyword = 'hello code';
$exloded = explode(' ', $keyword);
$query = 'SELECT * FROM A ';
$i = 0;
$params = array();
foreach ($exploded as $value):
if ($i == 0) {
$query .= ' WHERE `text` LIKE :value_'.$i;
} else {
$query .= ' OR `text` LIKE :value_'.$i;
}
$params[':value_'.$i] = '%'.$value .'%';
$i++;
endforeach;
$sth = $db->query($query);
$sth->execute($params);
$rows = $sth->fetchAll();
echo '<pre>';print_r($rows);echo '</pre>';
Build your query in loop(over your provided keywords) and assign unique placeholders in query to match for all values
Edit for full text search
Using full text search you can match exact same phrase with provided keyword,In order to work with full text search you need an index of type FULLTEXT.
ALTER TABLE `A` ADD FULLTEXT INDEX `fulltextindex` (`text`);
And query will be like
$keyword = 'hello code';
$exloded = explode(' ', $keyword);
$where = '';
$i = 0;
$select = array();
$params = array();
foreach ($exploded as $value):
$select[]= ' MATCH(`text`) AGAINST(:value_'.$i.' IN BOOLEAN MODE) ';
if ($i == 0) {
$where .= ' WHERE MATCH(`text`) AGAINST(:value_'.$i.' IN BOOLEAN MODE)';
} else {
$where .= ' OR MATCH(`text`) AGAINST(:value_'.$i.' IN BOOLEAN MODE)';
}
$params[':value_'.$i] = $value ;
$i++;
endforeach;
$query ='SELECT *,'. implode( ' + ',$select).' AS score FROM A '.$where.' ORDER BY score DESC';
$sth = $db->query($query);
$sth->execute($params);
$rows = $sth->fetchAll();
echo '<pre>';print_r($rows);echo '</pre>';
Above code will produce a query like
SELECT *,
MATCH(`text`) AGAINST('hello' IN BOOLEAN MODE)
+
MATCH(`text`) AGAINST('code' IN BOOLEAN MODE) AS score
FROM A
WHERE MATCH(`text`) AGAINST('hello' IN BOOLEAN MODE)
OR MATCH(`text`) AGAINST('code' IN BOOLEAN MODE)
ORDER BY score DESC
Alias score in above query will have value for each row and its matched score thus you can order your result in descending manner to show the records first which has a highest score.
Note: You can use Full text search in Myisam but for innodb you have
to upgrade your Mysql to 5.6 which supports full text searching in
innodb too
you can use the following code:
<?php
$keyword = 'hello code';
$exloded = explode(' ', $keyword);
$sql = "SELECT * FROM A WHERE ";
foreach($exploded as $value):
$sql .= "text LIKE '" . $value "%' OR ";
endforeach;
// remove last 'OR '
$sql = substr($sql, -3);
$result = mysqli_query($con, $sql);
//................
?>
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];