My application allows searching of articles. So when a user enters the string "articlex" the query works & results are show but when multiple words are entered "articlex articley" the query shows no results.
Cuurently I'm using this query
$querySub = 'SELECT * FROM table WHERE (col1 LIKE "%'.$search_string.'%") OR (col2 LIKE "%'.$search_string.'%") OR (col3 LIKE "%'.$search_string.'%")';
Where $search_string only contains the input by user
How can I make the query applicable for multiple words as well?
Example for PDO
/* Assume $pdo is already prepared as PDO instance. */
// search query split by spaces
$user_input = 'foo bar baz';
// create string for PDO::prepare()
$sql = 'SELECT * FROM testTable WHERE ';
$wheres = $values = array();
foreach (array_filter(explode(' ', $user_input), 'strlen') as $keyword) {
$wheres[] = 'col1 LIKE ?';
$values[] = '%' . addcslashes($keyword, '%_\\') . '%'; // this is escape for LIKE search
}
$sql .= $wheres ? implode(' OR ', $wheres) : '1';
// bind values and execute
$stmt = $pdo->prepare($sql);
$stmt->execute($values);
Example for mysql_** functions (deprecated)
/* Assume $link is already prepared as MySQL resource. */
// search query split by spaces
$user_input = 'foo bar baz';
// create string for mysql_auery()
$sql = 'SELECT * FROM testTable WHERE ';
foreach (array_filter(explode(' ', $user_input), 'strlen') as $keyword) {
$wheres[] = 'col1 LIKE ' . mysql_real_escape_string(
'%' . addcslashes($keyword, '%_\\') . '%',
$link
);
}
$sql .= !empty($wheres) ? implode(' OR ', $wheres) : '1';
// execute
$result = mysql_query($sql, $link);
While using variables for like query, you could use
Select * from table where keyword LIKE '%{$to_be_searched}%'
You can use REGEXP for this perpose .....or if you want multiple word search then you need to explode search string by space and then search this string from table using LIKE
if you search "articlex articley" then it will search whole word in LIKE operator
use only one "%" at the end. like
$querySub = SELECT * FROM table WHERE (col1 LIKE '$search_string%'");
This will search for both "articlex" and "articley"
1: This will be return should record
select * from products where title like "%word1%" or
title LIKE "word2";
note: if you have so many word then use dynamic query generator which generate title like "%word3%" or title like"%word4%" or ........
2: This will be return must records
select * from products where title like "%word1%word2%word3%";
Related
I´m trying to put together the most elegant way of searching in two fields for multiple (number of words can vary) terms that needs to only provide results when all words are found (AND instead of OR).
The below gives me an SQL syntax error message:
$search = $_GET["search"];
$searcharray = explode('|', $search);
$query=("SELECT username,sender,message,subject,timestamp,threadid,msgtype
FROM Messages WHERE ('" . implode("'|'",$searcharray) . "') IN CONCAT
(message,subject) ORDER BY timestamp");
I could of course set up a foreach loop for each match on the first word that breaks with an instruction to not add the result if any of the other words are not found in the two fields, but that´s alot more for the PHP script to handle, I think.
Any suggestions?
IN has to be followed by a list of values in parentheses, or a SELECT subquery. You can't use it for pattern matching.
To search a column for a word, you need to use LIKE, with % around the word. And there's no shortcut for searching for multiple words, you have to search for each of them and combine them with AND.
$tests = array_map(function($word) {
return "CONCAT(message, subject) LIKE '%$word%'";
}, $searcharray);
$where = implode(' AND ', $tests);
$query = "SELECT username,sender,message,subject,timestamp,threadid,msgtype
FROM Messages WHERE $where ORDER BY timestamp";
As mentioned in the comments, the code is suseptable to SQL injection. That being said, and since I don't want to re-write all of the code ;-), here's one way to construct the where clause.
$search = $_GET["search"];
$searcharray = explode('|', $search);
$qstr = "SELECT
`username`,
`sender`,
`message`,
`subject`,
`timestamp`,
`threadid`,
`msgtype`
FROM `Messages`
WHERE ";
$w = array();
foreach($searcharray as $key => $val) {
$w[] = "CONCAT(`message`,`subject`) LIKE '%" . $val . "%'";
}
$w_str = implode(" AND ",$w);
$qstr .= $w_str . " ORDER BY `timestamp`";
I have a table that contains information such as names, email-addresses, numbers etc.
Let's pretend that I have 30 contacts by the same name but they all live in different cities . How do I split the comma and replace it with and ....
Example
SELECT * WHERE name %$searchString% OR city %$searchString%...
Now if $searchString contains comma
SELECT * WHERE name %$searchString% OR city %$searchString%... AND SELECT * WHERE name %$searchString2% OR city %$searchString2%...
The $searchString2 contains information that's separated with comma.
Update
I want to search each row over and over again as many times as commas exist.
I'm sorry that I can't explain myself
This depends on whether you want to return rows where name or city match the search values exactly (=), or rows where any part of name or city match the search values (LIKE).
Regardless of which one you need, you can start out by converting your search string into an array of strings like this:
$strings = array_map('trim', explode(',', $searchString));
The array_map('trim'... ensures that you don't try to match any spaces before or after the commas in your comma-separated search string.
Here are examples for how to execute your query using prepared statements in PDO. First, full matches using IN:
$phs = rtrim(str_repeat('?,', count($strings)),',');
$stmt = $pdo->prepare("SELECT * FROM your_table WHERE name IN ($phs) OR city IN ($phs)");
// double the string values to us in both INs
$values = array_merge($strings, $strings);
$stmt->execute($values);
and partial matches using LIKE:
$sql = '';
foreach ($strings as $string) {
$sql .= ' name LIKE ? OR city LIKE ? OR';
$values[] = $string;
$values[] = $string;
}
$stmt = $pdo->prepare('SELECT * FROM your_table WHERE' . rtrim($sql, ' OR'));
$stmt->execute($values);
You need to use WHERE IN in SQL statement.
SELECT * WHERE name LIKE '%$searchString%' AND city IN ('city1', 'city2', 'city3'...)
Here is the good discussion on how to do it in PHP: Passing an array to a query using a WHERE clause
Something like this?
You will need to escape/clean the value of searchString.
<?php
// $searchString = "Cardiff,London,New York";
$SQL = 'SELECT * FROM table WHERE ';
$searchStrings = explode(',',$searchString);
$SQLArray = array();
foreach($searchStrings as $searchString) {
$SQLArray[] = "name LIKE '%$searchString%'";
$SQLArray[] = "city LIKE '%$searchString%'";
}
$SQL .= implode(' OR ',$SQLArray);
// print $SQL;
?>
I have an SQL LIKE query running on mySQL which runs fine on my local development server however on the production server it only works on single letters; i.e. if I enter a word any longer than one letter it returns no results.
Any ideas why and how I might be able to fix it?
Thank you in advance.
/**
* Searches all current vehicle listings for matches to given search string.
* #param string - Search keyword(s). Warning: If search string is empty all current vehicles are returned.
* #return array - Resulting table rows containing vin, imageFile, description, kms, auctioneerName, city, time.
*/
public function searchVehicles($search) { //
// Build up initial SQL query. Sub query returns all current vehicles
$query = "SELECT * FROM (SELECT vehicles.auctionId, vin, imageFile, CONCAT_WS(' ', year, makeName, modelName) as description, kms, auctioneerName, city, time FROM vehicles, models, makes, auctions, auctioneers, locations WHERE time > NOW() AND vehicles.modelId = models.modelId AND models.makeId = makes.makeId AND vehicles.auctionId = auctions.auctionId AND auctions.auctioneerId = auctioneers.auctioneerId AND auctions.locationId = locations.locationId) AS results WHERE";
$keywords = explode(" ", $search); // Break search into keywords
// Loop through each keyword in the search to build up SQL query
$firstLoop = true; // Initial loop flag
foreach ($keywords as $keyword) {
if (!$firstLoop) { // Check if this is not the first loop
$query = $query . " AND"; // Then: Add extension statement to query
} else {$firstLoop = false;} // Otherwise: Set flag to false
// Add each keyword search to the query ensuring case insensitivity by converting to uppercase
$query = $query . " UPPER(description) LIKE UPPER('%" . $this->escape($keyword) . "%')";
}
// Add ordering SQL
$query = $query . " ORDER BY time";
// Run query and return results (if any)
return $this->query($query);
}
$query = $query . " UPPER(description) LIKE '%" . strtoupper($this->escape($keyword)) . "%'";
try using COLLATE
$query = $query . " description COLLATE utf8_general_ci like '" . $this->escape($keyword) . ")%'";
for case insensitive search
Upper should be inside.
$query = $query . " UPPER(description) LIKE CONCAT('%',UPPER(" . $this->escape($keyword) . "),'%')";
I am trying to query:
$title2 = (isset($row_DetailRS1['r_bus_name']) ? $row_DetailRS1['r_bus_name'] : "");
$query_test = "SELECT *
FROM table
WHERE r_email = '$email2'
AND r_city != '$location2'
AND r_bus_name LIKE '%$title2%'
ORDER BY r_bus_name";
The r_bus_name LIKE '%$title2' is defined from above and is grabbing the TITLE of the EVENT from the POST. The title is usually two to three words...
How do I query r_bus_name LIKE (any of the words in the event title $title2)?
Because right now it is taking the whole value of $title2.. I need to split them up or explode them in words, so if the title is something like "Test title here" then "Tester title here" would match?
If you want to search on EACH of the words in the title, you would need to construct a query using OR operations to apply them to the same query.
It might look something like this:
// break apart the title using spaces
$title2 = (isset($row_DetailRS1['r_bus_name']) ? $row_DetailRS1['r_bus_name'] : "");
$title_keywords = explode(" ", $title2);
// construct conditions (Note the ampersand causes pass-by-reference)
foreach($title_keywords as &$keyword) {
$keyword = "r_bus_name LIKE '%".mysql_real_escape_string($keyword)."%'";
}
$keyword_search = "(" . implode(" OR ", $title_keywords) . ")";
$query_test = "SELECT *
FROM table
WHERE r_email = '".mysql_real_escape_string($email2)."'
AND r_city != '".mysql_real_escape_string($location2)."'
AND ".$keyword_search."
ORDER BY r_bus_name";
// ...
Assuming the table is MyISAM, you could use the native Full Text Search (FTS) functionality:
$query = sprintf("SELECT t.*
FROM YOUR_TABLE t
WHERE t.r_email = '%s'
AND t.r_city != '%s'
AND MATCH(t.r_bus_name) AGAINST('%s')
ORDER BY t.r_bus_name",
mysql_real_escape_string($email2),
mysql_real_escape_string($location2),
mysql_real_escape_string($title2) );
$result = mysql_query($query);
Sadly, MySQL doesn't support FTS on the InnoDB engine.
Addendum
I recommend using sprintf if you aren't using PDO/etc for prepared statements, to protect against SQL injection attacks.
Split title2 on spaces and do multiple likes:
$titleArray = split(" ", $title2);
$query_test = "SELECT *
FROM table
WHERE r_email = '$email2'
AND r_city != '$location2'
AND ("
foreach ($title as titleArray)
$query_test .= "OR r_bus_name LIKE '%$title%'"
$query_test .= "ORDER BY r_bus_name";
I'm making a search site where the user can either search by Business Name or the table rows cat1, cat2,cat3. The "cat" rows are in the same table as the business name. I have it set up so I return business info if I search for the correct business. But I need to have it show businesses that have the category name you searched for.
**Basically what I'm asking is for a get search (php) to either search for the name of businesses or one of three categories.
Any Help, would be greatly appreciated... Here is my code In case you need it(Though I think this should be a pretty easy task, maybe not though, I'm a PHP Beginner)
include('config.php');
$var = $_REQUEST['search'];
$trimmed = trim($var);
$search = ucfirst($var);
$result = mysql_query("SELECT * FROM gj WHERE name like '%$search%' ORDER by name") or trigger_error(mysql_error());
$num_rows = mysql_num_rows($result);
And then I am using a while loop to get all the code from it.
while($row = mysql_fetch_array($result))
{
$id=$row['id'];
$name=$row['name'];
$phone=$row['phone'];
$website=$row['website'];
$city=$row['city'];
$address=$row['address1'];
$zipcode=$row['zipcode'];
$addressmap = preg_replace('/\s/', '+',$address);
$citymap = preg_replace('/\s/', '+',$city);
echo"
include('config.php');
$searchfields = array('name', 'cat1', 'cat2', 'cat3', )
$cleandata = mysql_real_escape_string(trim(strtolower($_REQUEST['search'])));
$where = array();
foreach($searchfields as $field) {
$where[] = 'lcase('.$field.') like \'%.$cleandata.%\'';
}
$result = mysql_query('SELECT * FROM gj WHERE '.implode(' OR ', $where).' ORDER by name') or trigger_error(mysql_error());
$num_rows = mysql_num_rows($result);
I've added a variable cleandata which contains the cleaned request data (to prevent SQL injection).
I've created a variable searchfields which can be easily expanded to search on more fields.
To search on more fields simply expand the array data:
$searchfields = array('name', 'cat1', 'cat2', 'cat3', 'cat4', )
EDIT
Added case insensitive
EDIT Added PDO
Note that since I have written this answer the community has begun the deprecation process of the ancient mysql_*. See the red box? Instead you should learn about prepared statements and use either PDO or MySQLi. If you can't decide, this article will help to choose. If you care to learn, here is a good PDO tutorial.
A rewrite of the above answer using PDO would look like something like the following:
$dbConnection = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'pass');
$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$searchfields = array('name', 'cat1', 'cat2', 'cat3', )
$where = array();
foreach($searchfields as $field) {
$where[] = 'lcase(' . $field . ') LIKE :keyword';
}
$stmt = $dbConnection->prepare('SELECT * FROM gj WHERE ' . implode(' OR ', $where) . ORDER BY name);
$stmt->execute(array(
':keyword' => '%' . trim(strtolower($_REQUEST['search'])) . '%',
));
Lets say, you want to search for bussines name 'Jake' and category 'php'.
URL for your request will be like this...
http://yourdomain.com/search.php?name=Jake&category=php
You need to have some column, thats is unique identifier of table row. In this example I use 'id' column. Edit it to your needs. Now lets set up your query...
$query = "SELECT * FROM `gj`
WHERE name LIKE '%{$_GET['name']}%'
AND `gj.id` IN (
SELECT id FROM test
WHERE
cat1 LIKE '%{$_GET['category']}%' OR
cat2 LIKE '%{$_GET['category']}%' OR
cat3 LIKE '%{$_GET['category']}%'
)";
// or edit this cat1 LIKE '%{$_GET['category']}%'
// to cat1 = '{$_GET['category']}'
// if you want to compare exact values
With this query you retrieve data from DB
$result = mysql_query($query) or trigger_error(mysql_error());
Now do whatever you want with retrieved data.
Let me know the result ;-)