I have prepared a spreadsheet containing several entries, and each row of entry provides two columns of information. One is a product name, and another one is the price of the product. An Example is shown as follows:
Product (Column A) Price (Column B)
1. Watch $100
2. Mousepad $50
3. Notebook $1000
I am trying to create a web-based database with PHP and MYSQL. The basic searching function is that when I enter a sentence in a search box, such as "I have a watch and a notebook", those entries in my database matching some of the words in the sentence would be given (i.e. row 1 "Watch" and row 3 "Notebook"). Does MySQL support this kind of search, and how can I write the query to do so?
Writing an SQL query to do that would not be hard. All you need is to write a WHERE clause that searches for the column value inside your string. MySQL has a LOCATE() function you can use to search for substrings. In your example, you may have:
SELECT *
FROM myTable
WHERE LOCATE(product, 'I have a watch and a notebook.') <> 0;
It is important to note, as you'll see in the link, locate returns 0 if the substring is not found.
Here is an SQL Fiddle example.
Related
I have a search page in PHP which uses the following query to fetch content from the database.
SELECT * FROM linkBase WHERE (`title` LIKE '%".$s."%') OR (`descr` LIKE '%".$s."%')
Here is how my DB looks like :
id |title |descr
-----------------------------------------
1 |Hello World |This is a hello world description
2 |PiedPiper |The silicon valley company PiedPiper
3 |StackOverflow |Ask questions on programming
Now, for example, if I run this query with the value of $s = "silicon valley", Then it fetches the row 2. This is fine. But what if the user enters the search term as silicon PiedPiper. It returns no results with the above SQL query. How can I modify the query in such a way that it will return row 2 with the second search term too.
Question summery :
How can I do a search query using PHP and SQL in such a way that a result will be returned even if the the user enters two words which are not placed consequent to each other in the DB
If you need to support an arbitrary order of the words in the search I suggest using the REGEXP MySQL function with a simple "or" regular expression like
SELECT * FROM linkBase WHERE (`title` REGEXP 'silicon|PiedPiper') OR (`descr` REGEXP 'silicon|PiedPiper')
so you can replace the whitespace with PHP and replace them with a pipe symbol (|) and the order of the words don't matter anymore.
This will select all rows that contain at least one of the words, if you need to match all words in the list another regular expression might be necessary.
LIKE '%{".$s."}%' or to be old school INSTR(title, '{'.$s.'}') > 0
I have a list of keywords in a field called 'keywords' in a MYSQL database For example the keywords field in the record contains 3 sample records
KEYWORD LIST 1: tree,apple,banana,cherry,flower,red apple,pink cherry,cat,mouse
KEYWORD LIST 2: cat,mouse,apple,red apple,flower,red appleberry
KEYWORD LIST 3: apple, red appleberry, flower
The keyword list is NOT an array - just a text field in a mysql database that has a lot of other fields.
When I run a MYSQL SELECT query from what I've seen 'so far' there are two ways: a) like %% b) match against
Let's say I want to run a query against the word 'apple'
SELECT * where keywords like '%apple%' from table
This would bring up the records that contain the word 'apple' including the record above but it wouldn't necessarily give me any sequence of higher or lower. I'd have to do do the filtering of the results post query.
Supposing I was more detailed in my query, and chose 'red apple' it would still show a match, but I wouldn't necessarily get have KEYWORD LIST 1 be more relevant than 2 or 3.
Someone suggested using the Match Against instead
SELECT *, MATCH(Keywords) AGAINST('apple') AS Score
FROM table
WHERE Keywords like '%red apple%'
ORDER BY score DESC;
This is certainly heading in the right direction - however will it won't sort the results by an exact match being found as more relevant. The relevancy would be based on how many repetitions of the word 'apple' appeared in the keyword list (this is the age old reason why all the search engines chose to ignore keywords altogether) - do you see where I'm going with this?
What I'm looking for is do process most of the logic in the MYSQL instead of reading it into an array and processing it in PHP as others have suggested. Hence this simplistic example.
Here's what the query ought to how it should be:
1) if my query is 'apple' Keyword list 1 should show up first
2) if my query is 'red apple' then Keyword list 2 should show up First because the word 'red apple' is CLOSER to the FRONT of the keyword list - closer to the beginning of the string.
BUT because of the LIKE %%
Keyword List 3 would show up even though the match was 'red appleberry' instead of 'red apple'
(It would be simplest if MySQL had some kind of 'explode' function that you could specify the comma (',') as the delimiter in the match but I don't know of any such method, do you? Of course you'd have to read the entire list of results into an array and then explode them in PHP.
3) Suppose I search for 'red apple' and here's the bug: I'd still have a match on 'red appleberry' (record 3) - I don't want that. Record 2 should show up and then Record 1 and not even show record 3.
This is a discussion and an inquiry. Anyone have any suggestions?
My OWN ANSWER:
include the comma in the query
instead of searching for 'red apple' search for 'red apple,'
but what if the user put a space between - or if its at the tail end of the list of keywords?
QUESTION:
How can we search for specific SCORE in a comma delimited text field in MYSQL that uses the exact word (not a fragment) to come up with an ORDERED list of results.
Every attempt on this so far will still have Keyword List 3 show up higher than 2 even though red appleberry and red apple are two different phrases separated by commas.
Thanks! Let's discuss!
For small project, you can do something like this
SELECT *,
case when keyword like '%red apple%' then 1 else 0 end exact_match,
MATCH(Keywords) AGAINST('apple') AS Score
FROM table
where keywords like '%apple%'
ORDER BY exact_match DESC, score DESC;
I want to query a table as follows:
I have a field called "category" and my input match contains N separate words. I want the query to match all rows that contain all N words, but in any order.
For example if the field category contains "hello good morning world", my input query can contain "hello morning" or "good" or "world hello" and all are matches to the query.
How do I formulate such an SQL expression?
Also it would be good if the query can be made case insensitive.
If you are using MySQL you can use the boolean fulltext search feature to achieve this. You can put a + in front of each term and then only results with all the terms, in any order, will be returned. You will need to make sure the column containing the category field has a fulltext index specified on it for this to work. Other database engines probably have similar features. So for example you might do something like the following assuming there were a fulltext index over the category column...
SELECT * FROM myTable WHERE MATCH (category) AGAINST ('+term1 +term2 +term3' IN BOOLEAN MODE);
I would avoid using the "LIKE" operator as others have suggested you would have to worry about the headache of mixed upper/lower case and if you have a large database using a % in the front of a LIKE search term is going to cause a full table scan instead of using an index which is horrible for performance.
I'm not writing the loop that will build this query for you. This will get the job done, but it will be pretty inefficient.
SELECT * FROM table
WHERE (
TOUPPER(category) LIKE '*HELLO*' AND
TOUPPER(category) LIKE '*GOOD*' AND
TOUPPER(category) LIKE '*MORNING*' AND
TOUPPER(category) LIKE '*WORLD*'
);
You could also research using REGEXes with SQL.
I have a string query to search (assuming "this is my first query" as an example).
And I am also having a table which consists of (id, title, rating, ... ) attributes.
What I want is to find out the search results of my string query which match with "title" attribute (probable or exact both).
But what if complete text i.e. "this is my first query" is not there then there will be no results if I do like
SELECT * FROM test WHERE title LIKE '%$query%';
What I am trying to think next is to fire another query with lesser character this time.. i.e. I will fire the same query using search string "this is my first quer" (y is truncated) and so on until I get my desired no. of results.
But my problem is:
This is very costly operation
I want search data to be sorted in order of descending value of rating ( another field in "test" table)
Please help me out how can I proceed with this ?
Add index on this field and run query in loop. I don't like it.
Use fulltext searching http://dev.mysql.com/doc/refman/5.1/en/fulltext-search.htm in mysql.
Use standalone searching server like Sphinx http://sphinxsearch.com/
Say if I have an array and I want to check if an element is a part of that array, I can go ahead and use in_array( needle, haystack ) to determine the results. I am trying to see the PHP equivalent of this for my purpose. Now you might have an instant answer for me and you might be tempted to say "Use IN". Yes, I can use IN, but that's not fetching the desired results. Let me explain with an example:
I have a column called "pets" in DB table. For a record, it has a value: Cat, dog, Camel
(Yes, the column data is a comma separated value). Consider that this row has an id of 1.
Now I have a form where I can enter the value in the form input and use that value check against the value in the DB. So say I enter the following comma separated value in the form input: CAT, camel
(yes, CAT is uppercase & intentional as some users tend to enter it that way).
Now when I enter the above info in the form input and submit, I can collect the POST'ed info and use the following query:
$search = $_POST['pets'];
$sql = "SELECT id FROM table WHERE pets IN ('$search') ";
The above query is not fetching me the row that already exists in the DB (remember the record which has Cat, dog, Camel as the value for the pets column?). I am trying to get the records to act as a superset and the values from the form input as subsets. So in this case I am expecting the id value to show up as the values exist in the column, but this is not happending.
Now say if I enter just CAT as the form input and perform the search, it should show me the ID 1 row.
Now say if I enter just camel, cAT as the form input and perform the search, it should show me the ID 1 row.
How can I achieve the above?
Thank you.
The function you're looking for is find_in_set:
select * from ... where find_in_set($word, pets)
for multi-word queries you'll need to test each word and AND (or OR) the tests:
where find_in_set($word1, pets) AND find_in_set($word2, pets) etc
IN() Check whether a value is within a set of values
mysql> SELECT 2 IN (0,3,5,7);
-> 0
mysql> SELECT 'wefwf' IN ('wee','wefwf','weg');
-> 1
SELECT val1 FROM tbl1 WHERE val1 IN (1,2,'a');
View: IN MySql
I've got several things for you in terms of feedback & in direct response to your questions:
First, I suggest you sanitize the input. Everybody is going to tell you that. For that, see What’s the best method for sanitizing user input with PHP?.
Second, normalize the input with UPPER() or LOWER() if you want to use MySQL and need to store user-formatted input, or use strtoupper() and strtolower() if you wanted to process the input before storing it.
You're still left with the order in the user query. E.g. "cat, dog" ought to yield the same result as "dog, cat". If you were to code that with a LIKE statement, performance issues are going to eat you alive. Not only would you have to create the query dynamically, you'd also end up with huge and unnecessarily complex queries. In short, forget it. You have to change the way you store your data.
One way to accomplish this is by creating a relationship table that references a table of unique user input and your record. This table would look similar to
user_id | pet_id
Every user could have more than one pet_id associated with them. I've set up a database a long time ago the same way you did and ran into the same issues. Performance-wise it never paid off and it's anything but good style. I ended up changing my structure because of that to the above-mentioned method.
This mysql function search an INT value into a json array of INT:
-- EXAMPLES :
-- select is_into_json_array(18, '[25, 10, 15]'); -> -100
-- select is_into_json_array(25, '[25, 10, 15]'); -> 0
-- select is_into_json_array(15, '[25, 10, 15]'); -> 2
https://github.com/PietroLaGrotta/Json-in-mysql-text-type/blob/master/is_into_json_in_array.sql
Yes, the column data is a comma
separated value
Here is your fault.
No, it shouldn't be comma separated value
And your database structure should be normalized.