PHP explode and MySQL query to search in multiple columns - mysql

I have a form where I want a user to enter one or more words. These words should then match mutiple columns in a MySQL database.
I have started to build some code but I'm stuck.
<?php
$term = $_SESSION['session_searchstring']; //Let's say that session is John Doe
$searchterm = explode(' ',$term);
$searchFieldName = "name";
$searchCondition = "$searchFieldName LIKE '%" . implode("%' OR $searchFieldName LIKE '%", $searchterm) . "%'";
$sql = "SELECT * FROM students WHERE $searchCondition;";
echo $sql; //Echo to test what mysql_query would look like
?>
The above code will output:
SELECT * FROM students WHERE name LIKE '%John%' OR name LIKE '%Doe%';
The problem is that I want to search in multiple columns ($searchFieldName). I have for example
customer_firstname
customer_lastname
And I want to match my searchstring against the content of both columns.. How would I continue?

Perhaps
$term = $_SESSION['session_searchstring']; //Let's say that session is John Doe
$searchterm = explode(' ',$term);
$searchColumns = array("customer_firstname","customer_lastname");
for($i = 0; $i < count($searchColumns); $i++)
{
$searchFieldName = $searchColumns[$i];
$searchCondition .= "($searchFieldName LIKE '%" . implode("%' OR $searchFieldName LIKE '%", $searchterm) . "%')";
if($i+1 < count($searchColumns)) $searchCondition .= " OR ";
}
$sql = "SELECT * FROM students WHERE $searchCondition;";
echo $sql; //Echo to test what mysql_query would look like
Produces
SELECT * FROM students WHERE (customer_firstname LIKE '%John%' OR customer_firstname LIKE '%Doe%') OR (customer_lastname LIKE '%John%' OR customer_lastname LIKE '%Doe%');

If your table is of MyIsam type or you can convert it to MyIsam, use MySQL Fulltext Search. if not, anyway, you can build a long query like
SELECT * FROM students WHERE name LIKE '%John%' OR name LIKE '%Doe%' OR lastname LIKE "%John%" OR lastname LIKE "%Doe%"
or union your columns into one another just for search (but this both are not prefered).
Also a good approach is to use fulltext search engines like Sphinx.

In my case I needed all search phrases/terms to match at least one column, no search phrase/term could be a no-match.
I ended up tweaking the example from Kermit in the following way:
public function getRawWhereFilterForColumns($filter, $search_columns)
{
$search_terms = explode(' ', $filter);
$search_condition = "";
for ($i = 0; $i < count($search_terms); $i++) {
$term = $search_terms[$i];
for ($j = 0; $j < count($search_columns); $j++) {
if ($j == 0) $search_condition .= "(";
$search_field_name = $search_columns[$j];
$search_condition .= "$search_field_name LIKE '%" . $term . "%'";
if ($j + 1 < count($search_columns)) $search_condition .= " OR ";
if ($j + 1 == count($search_columns)) $search_condition .= ")";
}
if ($i + 1 < count($search_terms)) $search_condition .= " AND ";
}
return $search_condition;
}
I only needed the contents of the Where-clause since I'm using Laravel and could put that into the rawWhere-method.
usage:
$search_condition = $this->getRawWhereFilterForColumns
("John Doe", array("column1", "column2"));
which produces
(column1 LIKE '%John%' OR column2 LIKE '%John%')
AND (column1 LIKE '%Doe%' OR column2 LIKE '%Doe%')
And finally you use this $search_condition in whatever way suits you, for example:
$sql = "SELECT * FROM students WHERE $search_condition;";
Or in my Laravel-case:
$modelInstances = Model::whereRaw
($search_condition)->paginate(self::ITEMS_PER_PAGE);
Perhaps this is an improved solution for either David or anybody else visiting this thread, like me, even if it's almost two years after the original post.

Related

searching keywords with dynamic query

need quick help.
I am creating a dynamic MySQL query for keywords and wants to search only those keyword having more than 3 characters. I have created query but I don't know how to search only for more than three characters?
here is query I wrote
$returned_results = array ();
$where = "";
$keywords = preg_split('/[\s]+/', $keywords);
$total_keywords = count($keywords);
foreach ($keywords as $key=>$keyword)
{
$where .= "keywords LIKE '%$keyword%'";
if ($key != ($total_keywords - 1))
$where .= " OR ";
}
$query = "SELECT title, url FROM pages WHERE $where";
In the where clause you add the code below
and CHAR_LENGTH('keywords') > 3
With this clause you get the lines which keyword length it more than 3
You may use strlen to filter keywords which have length greater than 3 chars.
foreach ($keywords as $key=>$keyword){
if(strlen($keyword) > 3){
$where .= "keywords LIKE '%$keyword%'";
if ($key != ($total_keywords - 1))
$where .= " OR ";
}
}

sql query to search from 2 fields mysql Fulltext

I have a search that searches for songs in a database, currently they can search by artist or the title of the song. So at the moment they could search tom jones or its not unusual they couldn't search tom jones unusual. How do I make this possible my current SQL looks like this
SELECT *
FROM songs
WHERE artist LIKE '%$search%'
OR songname LIKE '%$search%'
LIMIT 6
I have added full text search to the artist and songname columns. Can't work out how to search on both rows.
Looks like you are using tom jones unusual as your search text '$search'. When you are using like in mysql it will search for the text pattern in the given field but when you enter tom jones unusual as the search text there are no occurrences for such a text. Because tom jones is in one field and unusual is in the other field
You can do following to get done what you want
get the full search text tom jones unusual
split the search text from the white spaces in to separate variables ex $ser1 = tom; $ser2 = jones; $ser3 = unusual;
then do something like this in mysql
select * from song where artist like '%$ser1%' or '%$ser2%' or '%$ser3%' or songname like '%$ser1%' or '%$ser2%' or '%$ser3%'
The solution to this is using full text search. You first need to define the rows you want to use in full text search you can do this with the following mysql command
ALTER TABLE songs
ADD FULLTEXT(artist, songtitle)
and then the sql query is
$sql = "SELECT * FROM songs WHERE MATCH (songname, artist) AGAINST ('$search') LIMIT 6";
This will return results only when there is a matching word if you want like results before a full word is typed you can so something like this.
$sql = "SELECT * FROM songs WHERE MATCH (songname, artist) AGAINST ('$search' IN BOOLEAN MODE) LIMIT 6";
$sqllike = "SELECT * FROM songs WHERE artist like '%$search%' OR songname like '%$search%' LIMIT 6";
$result = mysqli_query($con, $sql);
$resultlike = mysqli_query($con, $sqllike);
if (mysqli_num_rows($result) > 0) {
// output data of each row
while($row = mysqli_fetch_assoc($result)) {
echo "<a href='". $row["songid"] . "' class='songclicker'>";
echo "<div class='song whitefont'>";
echo "<img src='" . $row["artwork"]."' class='songimage'>";
echo "<p>". $row["songname"] . "</p>";
echo "<p>". $row["artist"] . "</p></div>";
}
echo "<a href='". urlencode($search) ."'><h1 class='seeall'>See all search results</h1></a>";
} else {
if (mysqli_num_rows($resultlike) > 0) {
// output data of each row
while($row = mysqli_fetch_assoc($resultlike)) {
echo "<a href='". $row["songid"] . "' class='songclicker'>";
echo "<div class='song whitefont'>";
echo "<img src='" . $row["artwork"]."' class='songimage'>";
echo "<p>". $row["songname"] . "</p>";
echo "<p>". $row["artist"] . "</p></div>";
}
echo "<a href='searchresults.php'><h1 class='seeall'>See all search results</h1></a>";
} else {
echo "0 results";
}
}

SQL search multiple values in same field

I'm building a simple search algorithm and I want to break my string with spaces, and search my database on it, like so:
$search = "Sony TV with FullHD support";
$search = explode( ' ', $search );
SELECT name FROM Products WHERE name LIKE %$search[1]% AND name LIKE %$search[2]% LIMIT 6
Is this possible?
Yes, you can use SQL IN operator to search multiple absolute values:
SELECT name FROM products WHERE name IN ( 'Value1', 'Value2', ... );
If you want to use LIKE you will need to use OR instead:
SELECT name FROM products WHERE name LIKE '%Value1' OR name LIKE '%Value2';
Using AND (as you tried) requires ALL conditions to be true, using OR requires at least one to be true.
Try this
Using UNION
$sql = '';
$count = 0;
foreach($search as $text)
{
if($count > 0)
$sql = $sql."UNION Select name From myTable WHERE Name LIKE '%$text%'";
else
$sql = $sql."Select name From myTable WHERE Name LIKE '%$text%'";
$count++;
}
Using WHERE IN
$comma_separated = "('" . implode("','", $search) . "')"; // ('1','2','3')
$sql = "Select name From myTable WHERE name IN ".$comma_separated ;
This will works perfectly in both cases, one or multiple fields searching multiple words.
Hope this will help someone. Thanks
declare #searchTrm varchar(MAX)='one two three four';
--select value from STRING_SPLIT(#searchTrm, ' ') where trim(value)<>''
select * from Bols
WHERE EXISTS (SELECT value
FROM STRING_SPLIT(#searchTrm, ' ')
WHERE
trim(value)<>''
and(
BolNumber like '%'+ value+'%'
or UserComment like '%'+ value+'%'
or RequesterId like '%'+ value+'%' )
)
This has been partially answered here:
MySQL Like multiple values
I advise against
$search = explode( ' ', $search );
and input them directly into the SQL query as this makes prone to SQL inject via the search bar. You will have to escape the characters first in case they try something funny like: "--; DROP TABLE name;
$search = str_replace('"', "''", search );
But even that is not completely safe. You must try to use SQL prepared statements to be safer. Using the regular expression is much easier to build a function to prepare and create what you want.
function makeSQL_search_pattern($search) {
search_pattern = false;
//escape the special regex chars
$search = str_replace('"', "''", $search);
$search = str_replace('^', "\\^", $search);
$search = str_replace('$', "\\$", $search);
$search = str_replace('.', "\\.", $search);
$search = str_replace('[', "\\[", $search);
$search = str_replace(']', "\\]", $search);
$search = str_replace('|', "\\|", $search);
$search = str_replace('*', "\\*", $search);
$search = str_replace('+', "\\+", $search);
$search = str_replace('{', "\\{", $search);
$search = str_replace('}', "\\}", $search);
$search = explode(" ", $search);
for ($i = 0; $i < count($search); $i++) {
if ($i > 0 && $i < count($search) ) {
$search_pattern .= "|";
}
$search_pattern .= $search[$i];
}
return search_pattern;
}
$search_pattern = makeSQL_search_pattern($search);
$sql_query = "SELECT name FROM Products WHERE name REGEXP :search LIMIT 6"
$stmt = pdo->prepare($sql_query);
$stmt->bindParam(":search", $search_pattern, PDO::PARAM_STR);
$stmt->execute();
I have not tested this code, but this is what I would do in your case.
I hope this helps.
You can try and execute below query:
SELECT name FROM Products WHERE REGEXP '.*Value1|.*Value2';
Pls note that there should not be a space before or after the pipe symbol
(|).
I know this is long time ago, but I have a solution. It can solved like this:
#intial query
query = 'SELECT var1, var2 FROM dbo.db_name WHERE'
if status :
query = query + " AND status='" + status + "'"
if type :
query = query + " AND Type='" + type + "'"
if number :
query = query + " AND Number='" + number + "'"
if cancel_request:
query = query + " AND CancelRequest='" + cancel_request + "'"
query = query + ' ORDER BY transid DESC'
cur.execute(query)

how would I change this over to do a full text search instead of LIKE?

after some researching I put this code together to search a mysql table in the db. while it works fine, it limit itself to match the words exactly as the user enters it. anyone know how to make it so that it matches my some sort of relevancy? I have been reading about the full text search but I cant really seem to grasp it.
for example, if you search for 'unanswered questions' in two fields, I want to be able to get result like that include the searched word(s) in any string that it show up in, and list it according to relevancy, like so (search results example output):
- unanswered questions
- answered questions
- answer question
- unanswered questions
- unanswered questions
- questions
- answer
$k = trim ($_GET['search']);
$i = "";
$terms = explode (" ", $k);
$query = "SELECT * FROM table1 WHERE ";
foreach ($terms as $each){
$i++;
if ($i == 1)
$query .= "fld_title LIKE '%$each%' OR fld_keyword LIKE '%$each%' ";
else
$query .= "OR fld_title LIKE '%$each%' OR fld_keyword LIKE '%$each%' ";
}
// connect
include_once "connect.php"; //connect 2 db
$query = mysql_query($query);
$numrows = mysql_num_rows ($query);
if ($numrows > 0){
while ($row = mysql_fetch_assoc ($query)){
//
//
// echo out something here
//
//
}
}else
{
echo "No results found for <b>$k</b>";
}
to do a fulltext search you have to:
Create a Fulltext index in the table (note the fields can't be BLOB)
ALTER TABLE tablename ADD FULLTEXT(field1, field2,...);
in your case:
ALTER TABLE table1 ADD FULLTEXT(fld_title, fld_keyword);
in php change
$k = trim ($_GET['search']);
$i = "";
$terms = explode (" ", $k);
$query = "SELECT * FROM table1 WHERE ";
foreach ($terms as $each){
$i++;
if ($i == 1)
$query .= "fld_title LIKE '%$each%' OR fld_keyword LIKE '%$each%' ";
else
$query .= "OR fld_title LIKE '%$each%' OR fld_keyword LIKE '%$each%' ";
}
for
$k = trim ($_GET['search']);
$query="SELECT * FROM table1 WHERE MATCH(fld_title, fld_keyword) AGAINST ('".$k."')";
if you want to see the relevancy of the results:
$query="SELECT *, MATCH(fld_title, fld_keyword) AGAINST ('".$k."') as relevancy FROM table1 WHERE MATCH(fld_title, fld_keyword) AGAINST ('".$k."')";
The MATCH-AGAINST returns a number: 0 for no match or other depending on matching.
You can "order by relevancy", change the query for make more relevant the search... MATCH(fld_title, fld_keyword) AGAINST ('".$k."') > 0.5
Only one problem: the AGAINST part ($k for you) must be greater than 3 characters.

MySql LIKE returns false if search term is same as entire string in the column, why is that?

So I have following as part of my query
SELECT * FROM $table WHERE columname LIKE '%$searchterm%'
I have tried taking out leading and/or ending wildcards meaning
SELECT * FROM $table WHERE columname LIKE '$searchterm%'
AND
SELECT * FROM $table WHERE columname LIKE '%$searchterm'
AND
SELECT * FROM $table WHERE columname LIKE '%$searchterm%' OR columname LIKE '$searchterm'
and also tried adding following to the query with no luck
OR columname = '$searchterm'
So when my search term is "myval" and if column has whole string "myval", I would like to have that selected. But ALL of my queries above, return false/return nothing where myval is searchterm and column value as full.
I can not use MATCH because this is not Full-Text index.
EDIT:
PHP Code:
$sterm = NULL;
$table = 'mytable';
if(isset($_GET['s'])) { $sterm = explode(" ", mysql_real_escape_string($_GET['s'])); }
if(isset($_POST['s'])) { $sterm = explode(" ", mysql_real_escape_string($_POST['s'])); }
if(!empty($sterm)){
$getdata = "SELECT * FROM $table WHERE termsi != 'Special' ";
foreach ($sterm as $value){
$getdata .= "AND netid_all LIKE '%$value%' OR netid_all = '$value' ";
} //End foreach
$getdata .= "LIMIT 10";
$result = mysql_query($getdata) or die(mysql_error());
$row = mysql_fetch_array($result, MYSQL_ASSOC);
while($row = mysql_fetch_array($result, MYSQL_ASSOC))
{
echo <<<PRINTALL
{$row[0]}, {$row[1]}, {$row[2]}, {$row[3]}, {$row[4]}, {$row[5]}, {$row[6]}, {$row[7]}, ' <br />'
PRINTALL;
} //End While
} //End If search exists
Okay So As you guys suggested, i tried PHPMyAdmin sql console and it works fine, so it would have to be by PHP!? so here it is.
I'd suggest writing your query building like this:
$fullvalues = array();
$partials = array();
foreach ($sterm as $value){
$partials[] = "(netid_all LIKE '%" . mysql_real_escape_string($value) . "%')";
$fullvalues[] = "'" . mysql_real_escape_string($value) . "'";
}
$partials = implode(' OR ', $partials);
$fullvalues = implode(', ', $fullvalues);
$sql = <<<EOL
SELECT *
FROM $table
WHERE (termsi != 'Special')
AND (($partials) OR (netid_all IN ($fullvalues));
EOL;
Assuming your search string is a b c, you'd get this query:
SELECT *
FROM yourtable
WHERE (termsi != 'Special')
AND (((netid_all LIKE '%a%') OR (netid_all LIKE '%b%') OR (netid_all LIKE '%C%')) OR (netid_all IN ('a', 'b', 'c')))
If your search requires that all terms be present, then change the 'OR' to 'AND' in the implode.
Well found it,
$row = mysql_fetch_array($result, MYSQL_ASSOC);
while($row = mysql_fetch_array($result, MYSQL_ASSOC))
Was the problem, earlier when I was testing things, anyhow, it should have been the following
$row = mysql_fetch_array($result, MYSQL_ASSOC);
while($row)