I'm trying to do a search function using php and MySQL. I need to search from two different columns, one for song title and one for artist and user can search using:
1. artist name.
2. song title.
3. both of them (without order)
4. there will be special characters for ex: ' (apostrophe)
This is what I have done but I need a more efficient way to do this. I have also thought using similar_text(); in php. Can anyone suggest me a better way to do this. Thank You
table: songs
|artist | title |
|----------------------|
|eminem | not afraid |
|kida | o'najr |
My code:
$search_value = $_POST["search_value"];
$query = "select * from `songs` where concat(`title`, `artist`) like '%$search_value%'";
You should use the SQL OR statement, better than CONCAT one in this case.
Combined with a space before and after what you search, this should give you the expected result !
(I mean if you search for 'raid' you will not find 'Eminem - Not Afraid', if you want to find it you have to search for 'afraid' for exemple ; If you want to sort the results by revelance, you will have to create indexes and use them, or use Levenshtein method or something else ...)
Don't forget to escape your data before using it in sql statements.
Btw if you want to make it case insesitive you will have to use blabla COLLATE UTF8_GENERAL_CI LIKE %what you search% blabla
// if you are using mysql_connect()
$search_value = ' '.mysql_real_escape_string($_POST["search_value"]).' ';
$query = "select * from `songs` where `title` like '%$search_value%' or `artist` like '%$search_value%'";
// if you are using PDO
$args[':search_value'] = '% '.$_POST["search_value"].' %';
$query = "SELECT * FROM `songs` WHERE `title` LIKE :search_value OR `artist` LIKE :search_value";
$qry = $PDO->prepare($query);
$res = $qry->execute($args);
For a multi-words search you can also use
// for mysql_connect()
$search_value = $_POST["search_value"];
$search_value = explode(' ', $search_value);
foreach($search_value as $k => $v){
$search_value[$k] = mysql_real_escape_string($v);
}
$search_value = ' '.implode(' % ', $search_value).' ';
// for PDO
$search_value = explode(' ', $_POST["search_value"]);
$search_value = implode(' % ', $search_value);
$args[':search_value'] = '% '.$search_value.' %';
You can simply use sql or statement if you don't want confusion .
$search_value = $_POST["search_value"];//check user input first than create a query.
$query = "select * from `songs` where `title` like '%$search_value%' or `artist` like '%$search_value%'";
Related
I am retrieving data from a database with php and MySQL as follows
$query = mysql_query("SELECT * FROM pictures WHERE (title LIKE '%$Search%' OR keywords LIKE '%$Search%') AND approved = 'YES' ORDER BY title ASC");
The query is correct and there are no errors and the query works fine for "title LIKE '%$Search%'" but the parameter "OR keywords LIKE '%$Search%'" is not retrieving data. The parameter "AND" also works correctly.
The keywords are stored in the database for example "pizza, restaurants, take away" but I don't see that is a problem.
My question is "What is the correct syntax for applying the "OR" parameter?
Remove the brackets around (title LIKE '%$Search%' OR keywords LIKE '%$Search%')
Those are generally used for subqueries.
$query = mysql_query("
SELECT * FROM pictures
WHERE title LIKE '%$Search%'
OR keywords LIKE '%$Search%'
AND approved = 'YES'
ORDER BY title ASC
");
https://dev.mysql.com/doc/refman/5.0/en/subqueries.html
Here is an example of a subquery, and pulled from the manual on MySQL.com:
SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2);
Edit:
Or try a different quoting method:
$query = mysql_query("
SELECT * FROM pictures
WHERE title LIKE '".%$Search%."'
OR keywords LIKE '".%$Search%."'
AND approved = 'YES'
ORDER BY title ASC
");
You could also try escaping your data:
$Search = mysql_real_escape_string($Search);
as an example. I don't know how you're assigning that variable.
phpMyAdmin test edit:
This is what I used inside phpMyAdmin:
SELECT * FROM table
WHERE col1 LIKE '%pizza%'
OR col2 LIKE '%pizza%'
AND col3 = 'YES'
ORDER BY col1 ASC
using pizza as the search keyword seeing that $Search will be based on the same keyword for you, where columns contain "large pizza" in one, and "pizza, take away, restaurants" in another.
Remember that, whatever you're using/assigning $Search to, must reside inside all your queried columns.
You may also want to make use of explode().
Here is an example pulled from https://stackoverflow.com/a/15289777/
<?php
$search = 'Gold Chain Shirt';
$bits = explode(' ', $search);
$sql = "SELECT name FROM product WHERE name LIKE '%" . implode("%' OR name LIKE '%", $bits) . "%'";
The above will generate this query:
SELECT name FROM product WHERE name LIKE '%Gold%' OR name LIKE '%Chain%' OR name LIKE '%Shirt%'
Sorry for taking some time but this is my working answer to my own question... not the prettiest syntax but it works without any string functions or explode functions. MySql can handle keywords quite well without any other functions being included:
$query = mysql_query("SELECT * FROM pictures
WHERE
title LIKE '%$Search%' AND featured IS NOT NULL AND streetview IS NOT NULL AND (id_user > '1') AND (status = '1')
OR
keywords LIKE '%$Search%' AND featured IS NOT NULL AND streetview IS NOT NULL AND (id_user > '1') AND (status = '1') ORDER BY title ASC");
Thank you all for your contributions
I am attempting to write a search algorithm, nothing too advanced but it isnt just WHERE field1 = 'searchtext'. I am trying to search all keywords across multiple fields.
I have done a bit of searching and it seems as though my take on the matter is not compliant with MySQL's use of 'IN' with other functions, however I cannot find anything that seems to suggest a better way either here on stackoverflow or using google on independant blogs and other tutorial sites.
$fields = array('type','suburb','postcode','address'); // Fields in db being searched
$queried = $db->real_escape_string($_REQUEST['keyword']); // Input from form
$keys = explode(" ",$queried); // Determine individual keywords
$sql = "SELECT * FROM `properties` WHERE "; // Beginning of SQL Statement
$frc = 0; // Field Counter
foreach($fields as $f){
$inner = ''; // Reset $inner each run
$irc = 0; // Reset Inner Counter each run
$frc++; // Increase Field Counter
if($frc != 1){ $sql .= " OR "; } // All except first runthrough
$sql .= "`".$f."` IN "; // `field` IN
foreach($keys as $k){
$irc++; // Increase inner counter
if($irc == 1){
$inner .= "('%".$k."%'"; // First Inner per run (aka each keyword)
}else{
$inner .= ", '%".$k."%'"; // All other Inners
}
}
$inner .= ")"; // Inner finishes run before reset
$sql .= $inner; // Add Inner to SQL ready for query
}
$sql .= ";"; // Clean finish to SQL statement
$SearchProperties = $db->query($sql); // Run Query
I have included commentary to help you understand my messy code and what I felt I was doing. The code is giving me the expected output, for example if I search the keyword "house" my output is as follows;
$queried = house 3064
$sql = SELECT * FROM `properties` WHERE `type` IN ('%house%', '%3064%') OR `suburb` IN ('%house%', '%3064%') OR `postcode` IN ('%house%', '%3064%') OR `address` IN ('%house%', '%3064%');
Within the type column there is house and townhouse, it should be able to hit both, and should hit anything with the postcode 3064 regardless of if it has house in another column (According to what I want to accomplish)
However after several hours of searching, although my output is as desired I don't believe it to be correct. Could anybody help shed some light on the CORRECT method of solving my quandry and WHY this does not work? I always like to understand and learn from these sort of misunderstandings.
Thank you for your help.
If you have wildcards, you want like rather than in:
SELECT *
FROM `properties`
WHERE (`type` LIKE '%house%') OR
(`suburb` LIKE '%house%') OR
(`postcode` LIKE '%house%') OR
(`address` LIKE '%house%');
However, I would strongly suggest that you investigate full text indexes (see here). The use of MATCH() may greatly simplify your efforts.
EDIT:
Your query is still incorrect. And you should still be using like:
SELECT *
FROM `properties`
WHERE (`type` LIKE '%house%' or type like '%3064%') OR
(`suburb` LIKE '%house%' or suburb like '%3064%') OR
(`postcode` LIKE '%house%' or postcode like '%3064%') OR
(`address` LIKE '%house%' or address like '%3064%');
Try change 'IN' to 'LIKE'.
For example
$queried = house
$sql = SELECT * FROM `properties` WHERE
`type` LIKE '%house%'
OR `suburb` LIKE '%house%'
OR `postcode` LIKE '%house%'
OR `address` LIKE '%house%';
If you have a several keywords, then you need change query.
For example
$queried = house 3064
$sql = SELECT * FROM `properties` WHERE
(`type` LIKE '%house%' AND `type` LIKE '%3064%')
OR (`suburb` LIKE '%house%' AND `suburb` LIKE '%3064%')
OR (`postcode` LIKE '%house%' AND `postcode` LIKE '%3064%')
OR (`address` LIKE '%house%' AND `address` LIKE '%3064%');
I am making an autocomplete form and requesting names from my database. This is the table in my database
user_id | firstname | lastname
I can get the data for a "searchterm" using this
$query = "SELECT user_id, firstname, lastname FROM users WHERE firstname like :searchterm ";
But I want to expand it so I could also search both firstname and lastname at the same time, for example, to search for "John D...". I think there is a way to join the two columns and then make a search. Can someone explain it?. I am just starting with this mysql thing.
When you've got spaces in your search term, you'll often need to split the string into sections before you put it into your query. Use AND if you want to match all inputted search terms, or OR if you want to match any. Example:
Search: john james smith
<?php
$search = "john james smith";
$bits = explode(" ", $search);
foreach($bits as $key => $bit) {
$bits[$key] = '(`field1` LIKE "' . $bit . '" AND `field2` LIKE "' . $bit . '")';
}
$sql = implode(' OR ', $bits);
// (`field1` LIKE "john" AND `field2` LIKE "john") OR (`field1` LIKE "james" AND `field2` LIKE "james") OR (`field1` LIKE "smith" AND `field2` LIKE "smith")
?>
Demo: https://eval.in/66808
Looks like you're using PDO (which is good), so you'll just need to put your binding parameters into that string instead, then concatenate it on at the end of your current SQL query into the WHERE clause.
I currently use a mysql statement like the one below to search post titles.
select * from table where title like %search_term%
But problem is, if the title were like: Acme launches 5 pound burger and a user searched for Acme, it'll return a result. But if a user searched for Acme burger or Acme 5 pound, it'll return nothing.
Is there a way to get it to return results when a users searches for more than one word? Is LIKE the correct thing to use here or is there something else that can be used?
You could use a REGEXP to match any of the words in your search string:
select *
from tbl
where
title REGEXP CONCAT('[[:<:]](', REPLACE('Acme burger', ' ', '|'), ')[[:>:]]')
Please notice that this will not be very efficient. See fiddle here.
If you need to match every word in your string, you could use a query like this:
select *
from tbl
where
title REGEXP CONCAT('[[:<:]]', REPLACE('Acme burger', ' ', '[[:>:]].*[[:<:]]'), '[[:>:]]')
Fiddle here. But words have to be in the correct order (es. 'Acme burger' will match, 'burger Acme' won't). There's a REGEXP to match every word in any order, but it is not supported by MySql, unless you install an UDF that supports Perl regexp.
To search for a string against a text collection use MATCH() and AGAINST()
SELECT * FROM table WHERE MATCH(title) AGAINST('+Acme burger*')
or why not RLIKE
SELECT * FROM table WHERE TITLE RLIKE 'Acme|burger'
or LIKE searching an array, to have a compilation of $keys
$keys=array('Acme','burger','pound');
$mysql = array('0');
foreach($keys as $key){
$mysql[] = 'title LIKE %'.$key.'%'
}
SELECT * FROM table WHERE '.implode(" OR ", $mysql)
What you need to do is construct a SQL such that, for example:
select * from table where title like "%Acme%" and title like "%burger%"
In short: split the string and create one like for each part.
It might also work with replacing spaces with %, but I'm not sure about that.
The best thing is thing use perform union operation by splitting your search string based on whitespaces,
FOR Acme 5 pound,
SELECT * FROM TABLE WHERE TITLE LIKE '%ACME 5 POUND%'
UNION
SELECT * FROM TABLE WHERE TITLE LIKE '%ACME%'
UNION
SELECT * FROM TABLE WHERE TITLE LIKE '%5%'
UNION
SELECT * FROM TABLE WHERE TITLE LIKE '%POUND%'
Find out a way to give the first query a priority. Or pass the above one as four separate queries with some priority. I think you are using front end tp pass query to data bases, so it should be easy for you.
<?php
$search_term = 'test1 test2 test3';
$keywords = explode(" ", preg_replace("/\s+/", " ", $search_term));
foreach($keywords as $keyword){
$wherelike[] = "title LIKE '%$keyword%' ";
}
$where = implode(" and ", $wherelike);
$query = "select * from table where $where";
echo $query;
//select * from table where title LIKE '%test1%' and title LIKE '%test2%' and title LIKE '%test3%'
When I replace
$ordering = "apples, bananas, cranberries, grapes";
with
$ordering = "apples, bananas, grapes";
I no longer want cranberries to be returned by my query, which I've written out like this:
$query = "SELECT * from dbname where FruitName LIKE '$ordering'";
Of Course this doesn't work, because I used LIKE wrong. I've read through various manuals that describe how to use LIKE and it doesn't quite make sense to me.
If I change the end of the db to "LIKE "apples"" that works for limiting it to just apples. Do I have to explode the ordering on the ", " or is there a way to do this in the query?
LIKE is normally used for partially matching strings, e.g. you'd use
WHERE fruitname LIKE 'app%'
to find 'apple' and 'apples'.
What you (probably) want is the IN clause, e.g.
WHERE fruitname IN ('apples', 'bananas', 'grapes')
It probably should be:
SELECT * FROM database WHERE FruitName IN ('apples','bananas','grapes')
You need to explode the string and convert it to the appropriate SQL. This is probably the SQL syntax you want to end up with:
SELECT * FROM dbname WHERE FruitName IN ('apples', 'bananas', 'grapes')
PHP code:
$fruits = array();
foreach (explode(', ', $ordering) as $fruit) {
$fruits[] = "'" . mysql_real_escape_string($fruit) . "'";
}
$fruits = implode(', ', $fruits);
$sql = "SELECT * FROM dbname WHERE FruitName IN ($fruits)";
try using
SELECT * from dbname WHERE FruitName IN ('apples','bananas','grapes')
if you need the result to be in the same order as the IN list extend the query with and ORDER BY
SELECT * from dbname WHERE FruitName IN ('apples','bananas','grapes') ORDER BY FruitName