I would like to ask about an issue i'm facing.
I have the full name in 1 column stored, example: "John Doe".
But on perform a search for example:
SELECT * FROM client WHERE name LIKE '%Doe John%';
Result: 0 Rows.
If i switch to the exact match store in database it found a row.
SELECT * FROM client WHERE name LIKE '%John Doe%';
Result: 1 Row.
My question is, how to do to search in database without taking the order of word.
In OOP framework the code is:
$like = 'Doe John';
$this->db->select('*')->from('client')->like('name', $like)->get();
Also i tested this but i got the same result:
$this->db->select('*')->from('client');
if($this->containTwoWords($like)) {
$explode = explode(' ', $like);
foreach($explode as $exploded){
$this->db->like('name', $exploded);
}
} else {
$this->db->like('name', $like);
}
$this->db->get();
function containTwoWords($like){
if(strpos($like, ' ') !== false) {
return true;
}
return false;
}
If somebody passed trough this and has better solution i appreciate the sharing !.
One option for your example case would be to check for the first and last names separately:
SELECT * FROM client WHERE name LIKE '%Doe%' AND name LIKE '%John%'
If you have exhausted such tricks with the LIKE operator, then you can look into using MySQL's full text search capabilities.
Try something like this:
<?php
$search_term = 'john doe abc';
$keywords = explode(" ", preg_replace("/\s+/", " ", $search_term));
foreach($keywords as $keyword){
$wherelike[] = " name LIKE '%$keyword%' ";
}
$where = implode(" and ", $wherelike);
$query = "select * from client where $where";
echo $query;
//select * from client where name LIKE '%john%' and name LIKE '%doe%' and name LIKE '%abc%'
?>
Try this name like '%John%' and name like '%Doe%'
If you are wanting to explode the $like variable into first/last name (and you always expect 2 names, separated by a space), then this should work for you.
PHP has the built-in explode() method which does exactly what you are asking.
$like = "John Doe";
$name = explode(" ", $like);
// This created a 0-based array, meaning the first item as split
// by the space between John and Doe is given the array index of 0.
// $name[0] = John
// $name[1] = Doe
So in practice with MySQL that could be used as the following:
$query = "SELECT * FROM client WHERE name LIKE '%" . $name[0] . "%' AND name LIKE '%" . $name[1] . "%'";
For more information on the explode() function, check out the PHP manual at: http://php.net/manual/en/function.explode.php
Hope this helps!
Related
Using single Chinese characters in my search.
分坨坨 is my example here. The last two (坨坨) are completely the same - duplicates, if you will.
My first variable is $where which looks like this:
$where = array();
foreach ( $qtwo as $word ) {
$where[] = "CHS LIKE '%" . $word . "%'";
}
$where = implode(' OR ', $where);
Which prints:
CHS LIKE '%分%' OR CHS LIKE '%坨%' OR CHS LIKE '%坨%'
(The following is not really consequential but helps to explain my variables:)
I get them into an array called $where3 - which prints like this:
ORDER BY CASE CHS
WHEN '分' THEN 1
WHEN '坨' THEN 2
WHEN '坨' THEN 3
My query looks like this:
{$results4 = $db->query("SELECT * FROM FOUR WHERE $where $where3
END;");
while ($row4 = $results4->fetchArray()) {
So they print in the order that they came in - and all duplicates are represented in both variables.
When I run the query though - only the first of the duplicates gets printed back (坨).
How can I get it to print both of the duplicates?
I have a mysql query which simply looks into mysql to find LIKE strings and displays the result.
Within the same mysql query, I have 2 LIKE.
1 is always a single string and the other one can be single and sometimes multiple strings separated by commas.
when I use my code, I get no results at all even though I have all the fields in the mysql database and I also have all the search strings in the columns.
This is my code:
$area = 'London';
$res = 'santandar, HSBC, RBS, ';
$sql = "SELECT * FROM banks WHERE location LIKE '%$area%' AND name LIKE '%$res'";
I also tried it with preg_match and it didn't return anything:
$sql = "SELECT * FROM banks WHERE location LIKE '%$area%' AND name LIKE '".preg_match($res)."'";
If I remove the second LIKE and my code looks like below, it works just fine:
sql = "SELECT * FROM banks WHERE location LIKE '%$area%'";
So the issue starts when I try to search using a comma separated string.
Could someone please advise on this issue?
EDIT:
The PHP varibles are POSTS so they can be anything in each post.
they are like so:
$area = $_POST['area'];
$res = $_POST['res'];
you should use an OR condition:
$res_array = explode(',' $res)
$num_elem= count($res_array) // with this value you can build dinamically the query
"SELECT * FROM banks WHERE location LIKE '%$area%'
AND ( name LIKE concat('%', $res_array[0]),
OR LIKE concat('%', $res_array[1])
OR LIKE concat('%', $res_array[2]) ";
You are going to need to blow this out into separate LIKEs with an OR, such as:
...WHERE location LIKE '%{$area}' AND (name LIKE '%{$name1}%' OR name LIKE '%{$name2}' OR ...)
You could write this fairly simply with some PHP logic:
function build_like_or( $values, $field_name ) {
// Create an array from the comma-separated values
$names = explode( ',', $values );
// Trim all the elements to remove whitespaces
$names = array_map( 'trim', $names );
// Remove empty elements
$names = array_filter( $names );
$where = array();
// Loop over each, placing the "LIKE" clause into an array
foreach( (array)$names AS $name ) {
$where[] = "{$field_name} LIKE '%{$name}%'";
}
// Glue up the LIKE clauses.
$where = '(' . implode(' OR ', $where) . ')';
// Results will be something like:
// $where = "(name LIKE '%santadar%' OR name LIKE '%HSBC%')"
return $where;
}
Usage:
$area = 'London';
$res = 'santandar, HSBC, RBS, ';
$name_where = build_like_or( $res, 'name');
$sql = "SELECT * FROM banks WHERE location LIKE '%$area%' AND {$name_where}";
// echo $sql outputs "SELECT * FROM banks WHERE location LIKE 'London' AND (name LIKE '%santadar%' OR name LIKE '%HSBC%' OR name LIKE '%RBS%')
My code let me perform search, as long as the order of the words is correct.
Let's say I'm searching for big dog, but I also want to search for dog big. It get more complicated with 3 or more words.
Is there a way to create a SQL query which would let me search through values with any order?
Only way I can think of this is by having multiple queries, where I change order of PHP variables manually...
<?php
if(isset($_GET['query']) && !empty($_GET['query'])) {
$query = $_GET['query'];
$query_array = explode(' ', $query);
$query_string = '';
$query_counter = 1;
foreach($query_array as $word) {
$query_string .= '%' . $word . (count($query_string) == $query_counter++ ? '%' : '');
}
$query = "SELECT * FROM pages WHERE Name LIKE '$query_string'";
$result = sqlsrv_query($cms->conn, $query);
while($row = sqlsrv_fetch_array($result)) {
extract($row);
echo ''.$Name.'<br>';
}
sqlsrv_free_stmt($stmt);
}
else {
//echo 'NO GET';
}
?>
You could assemble your conditions and check for each word on it's own:
$query_array = explode(' ', $query);
$queryParts = array();
foreach ($query_arra AS $value){
$queryParts[]="Name like '%".mysql_real_escape_string($value)."%'";
}
$searchString = implode(" AND ", $queryParts);
The Search string would now be Name like '%big%' AND Name like '%dog%' ... depending on how much search-keywords have been there.
I use the same approach very often, also when it is required that ALL keywords appear in at least ONE of the columns. Then you need one more loop to create the required AND conditions:
$search = "Big Dog";
$keywords = explode (" ", $search);
$columns = array("Name", "description");
$andParts = array();
foreach ($keywords AS $keyword){
$orParts = array();
foreach($columns AS $column){
$orParts[] = $column . " LIKE '%" . mysql_real_escape_string($keyword) . "%'";
}
$andParts[]= "(" . implode($orParts, " OR ") . ")";
}
$and = implode ($andParts, " AND ");
echo $and;
this would produce the query part (Name like '%Big%' OR description like '%Big%') AND (Name like '%Dog%' or description like '%Dog%')
So, it will find any row, where dog and big are appearing in at least one of the columns name or description (could also be both in one column)
Since your original querystring is something like %big%dog%, so I assume you are okay with matching big wild dog. In this case, you can just use the AND operator.
(Name LIKE '%big%" and Name LIKE '%dog%")
myisam supports full text search:
http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html
One thing you could look into is Full Text Search for ms sql server.
https://msdn.microsoft.com/en-us/library/ms142571.aspx
it's similar to a "search engine" in that it works off of an algorithm to rank results and even similar words (think thesaurus type lookups)
It's not exactly trivial to set up, but it's easy enough to find a tutorial on the subject and how to query from FTS (as the syntax is different than say LIKE '%big%dog%')
Here's a sample query from the page linked above:
SELECT product_id
FROM products
WHERE CONTAINS(product_description, ”Snap Happy 100EZ” OR FORMSOF(THESAURUS,’Snap Happy’) OR ‘100EZ’)
AND product_cost < 200 ;
i have a variable and an user_name i want to search on a string(function_description) of the user_name for it
whats wrong with this :
$function_keywords = mysql_real_escape_string($_POST['function_keywords']);
if($function_keywords=="" || empty($function_keywords)){
redirect("show.php?functions=PHP");
}
//trim whitespace from the stored variable
$trimmed = trim($function_keywords);
//separate key-phrases into keywords
$trimmed_keywords = explode(" ",$trimmed);
// Build SQL Query for each keyword entered
foreach ($trimmed_keywords as $trimm){
// MySQL "MATCH" is used for full-text searching.
//this code is ebv weird , should check out soon!
$query = "SELECT *
FROM functions
WHERE isEnabled=1 AND isPrivate=0
AND function_description LIKE '{$trimm}'
AND user_name='{$user_name}'
";
// Execute the query to get number of rows that contain search kewords
$results=mysql_query ($query,$connection);
as far as "like" syntax goes you have to use the '%' symbol. if you query for
select * from table where column like '%yourkeyword%'
then it returns any rows with 'yourkeyword' inside the table column.
your statement will be true only if the column = 'yourkeyword'
That's highly inefficient. If someone puts in 5 keywords, you'd be running the search 5 times and getting 5 sets of results. Try something more along these lines:
$words = $_POST['function_keywords'];
if ($words == '') {
... abort ...
}
$parts = trim(explode(' ', $words));
$clauses = array();
foreach($parts as $part) {
$clauses[] = "function_description LIKE '%" . mysql_real_escape_string($part) . "%'";
}
$clause = implode(' OR ' , $clauses);
$sql = "SELECT .... WHERE (isEnabled=1) AND (isPrivate=1) AND (user_name='$user_name') AND ($clause)";
$result = mysql_query($sql) or die(mysql_error());
This'll build up a long series of or statements for each keyword specified, and run the whole thing as a single query.
To see if the function_description contains the keyword you need to use '%' which stands for anything much the way '*' does in unix. Try function_description LIKE '%{$trimm}%'
I am trying to have a search result for someones name exploded then the first name and last name each search against each field 'first' and 'last'.
But need to leave room what if someone search for first last midle name like = $who = James David Smith it will exploded it and search each of the names against the first column and the last column. Incase the user inputs the name lastname first or adds a middle name.
Here is what i have so far but im stuck. Help. Please.
<?
$search = explode(' ', $who);
$limit=verify($get['page'])?" limit ".($get['page']*10).",10":" limit 10";
$q="select * from users where (first IN('%$search[]%') or last IN('%$search[]%') or full_name LIKE '%".$get['who']."%') AND (city LIKE '%".$get['where']."%' or province LIKE '%".$get['where']."%') order by province";
$rows=get_recordset($q);
if(count($rows)){
foreach($rows as $row){
echo $q;
?>
I am not sure I got you but if what you mean is :
When you have 3 names then - check all names against all three fields (first,last,fullname).
When you have only 2 names then - check first name against first field and last name against last field
then this should get it done:
$search = explode(' ', $who);
if (count($search) >2) { // in case we do got a middle name -
$whereNameStringsArr = array();
foreach ($search as $val) {
$whereNameStringsArr[] = " first LIKE '%$val%'
OR last LIKE '%$val%'
OR full_name LIKE '%$val%' ";
}
$whereNameClause = implode(" OR ",$whereNameStringsArr);
} else { // in case we don't got a middle name
$whereNameClause = " first LIKE '%{$search[0]}%'
OR last LIKE '%{$search[1]}%' ";
}
$limit=verify($get['page'])?" limit ".($get['page']*10).",10":" limit 10";
$q="select * from users where ($whereNameClause)
AND (city LIKE '%".$get['where']."%' or province LIKE '%".$get['where']."%')
order by province
$limit";
$rows=get_recordset($q);
....
Of course - make sure you validate all data you get from user's input
So why not do a fuzzy search? When you explode the data, do something like this:
$name = $_POST['name'] // John Michael Smith
$first_name = substr($name, 0, strrpos($name, ' ')); //Returns everything before last space, ie John Michael
$last_name = strstr($name, ' '); //Returns everything after first space, ie John Michael
Now you just run the mysql query but set it to look for anything that contains the above values (substring search) using LOCATE:
$results = mysql_query("SELECT * FROM names
WHERE LOCATE(firstname, '$first_name') > 0 OR
LOCATE(lastname, '$last_name') > 0
ORDER BY lastname
I'll assume you know what to do with the results.
Quick Update, If you are worried about users entering in Last Name First Name Middle, or what have you, you could always use the above but do a locate on the entire string:
$results = mysql_query("SELECT * FROM names
WHERE LOCATE(firstname, '$name') > 0 OR
LOCATE(lastname, '$name') > 0
ORDER BY lastname
This will check both columns for any instances of any of the string. You should probably (after sanitizing the string, as was rightly suggested already) also remove any commas (but not hyphens) in case someone enters last,first or what have you. replace them with spaces and then reduce all multi-spaces to one space to be double sure.
Sorry about that. Here is the way to split the names (by blanks). There as a problem with my substr syntax:
$name = $_POST['name'] // John Michael Smith
$first_name = substr($name, 0, strrpos($name, ' ')); //Returns everything before last space, ie John Michael
$last_name = strstr($name, ' '); //Returns everything after first space, ie John Michael