searching keywords with dynamic query - mysql

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 ";
}
}

Related

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)

SQL Like Statement with multiple WHERE clauses

I am having an issue getting this to work. I have multiple WHERE statements that need to happen based on conditional information from the search query. Within there I can't seem to get the LIKE statements to work.
In the database the STREET_NUM & STREET_NAME are in different rows. I am using one input field to check against called $address
I am also struggling with getting the MIN & MAX to work.
Here is the Query:
$sql = "SELECT * FROM arc_property_res WHERE ( arc_property_res.STATUS = 'Active'";
if(!empty($_GET['city'])){
// City only query!
$sql .= "AND arc_property_res.CITY = '{$_GET['city']}'";
}
if(!empty($_GET['neighborhood'])){
// Hood only query!
$sql .= "AND arc_property_res.SUBDIVISION = '{$_GET['neighborhood']}'";
}
if(!empty($_GET['mls-number'])){
// MLS only query!
$sql .= "AND arc_property_res.MLS_ACCT = '{$_GET['mls-number']}'";
}
if(!empty($_GET['min-price']) && !empty($_GET['max-price'])){
// MIN AND MAX only query!
$sql .= "AND arc_property_res.LIST_PRICE = MIN('{$_GET['min-price']}') MAX('{$_GET['max-price']}')";
}
if(!empty($_GET['num-of-beds'])){
// BEDS only query!
$sql .= "AND arc_property_res.BEDROOMS = '{$_GET['num-of-beds']}'";
}
if(!empty($_GET['num-of-baths'])){
// BATHS only query!
$sql .= "AND arc_property_res.BATHS_FULL = '{$_GET['num-of-baths']}'";
}
if(!empty($_GET['mls-number'])){
// BATHS only query!
$sql .= "AND arc_property_res.MLS_ACCT = '{$_GET['mls-number']}'";
}
if(!empty($_GET['address'])){
$sql .= "AND arc_property_res.STREET_NUM LIKE '%{$_GET['address']}'";
$sql .= "OR arc_property_res.STREET_NAME LIKE '{$_GET['address']}%'";
}
$sql .= ") ORDER BY {$orderby}{$price_order}{$comma}{$list_date}";
I think all you need are some parentheses around the arc_property_res.STREET_NUM. Further, I would recommend you add some spaces around each line in your entire code so that you don't get syntax errors.
if(!empty($_GET['address'])){
$sql .= " AND (arc_property_res.STREET_NUM LIKE '%{$_GET['address']}' ";
$sql .= " OR arc_property_res.STREET_NAME LIKE '{$_GET['address']}%') ";
}
In addition to the obvious "Bobby Tables" issue that your query has, the problem at hand is that you do not insert a space in front of AND. This results in queries that look like this:
AND arc_property_res.BEDROOMS =3AND arc_property_res.BATHS_FULL =2
Note that there is no space between 3 and AND - a syntax error.
You should look into parametrizing your queries, and modifying it in a way that ignores the parameters that have been set to NULL.
SELECT * FROM arc_property_res WHERE ( arc_property_res.STATUS = 'Active'
AND (arc_property_res.CITY = #cityParam OR #cityParam is NULL)
AND (arc_property_res.SUBDIVISION = #subdiv OR #subdiv is NULL)
...
)
This modification would let you keep the query the same regardless of the number of parameters that were actually set, get you the same results, taking pretty much the same time.
$sql .= "AND arc_property_res.LIST_PRICE = MIN('{$_GET['min-price']}') MAX('{$_GET['max-price']}')";
The min and max functions are for when you want to get the min and max of a field in your database.
What you want is to compare the list price to see if it falls in between the min and max values supplied by the user.
$sql .= " AND arc_property_res.LIST_PRICE >= '{$_GET['min-price']}' AND arc_property_res.LIST_PRICE <= '{$_GET['max-price']}'";

PHP explode and MySQL query to search in multiple columns

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.

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)