I want to make a search function in my website. I want to search for a string in all fields of my table (about 13 columns). If one row contains a field that matches the string (like operator) I want it to be added to result.
Example
|field 1 | field 2 | field 3|
some string test
test some string
one simple string
Now basically if I search for the string "test" I want to have the first two rows.
Is there a wildcard option for WHERE that I could do something :
SELECT * from my.table WHERE * like '%string%';
There is no such syntax in PostgreSQL (or any other DBMS).
As Spudley pointed out using a query like like '%string%' will be quite slow.
If this is something that is needed very often you should definitely look into PostgreSQL's full text search capabilities.
Related
I have a search input box where a user can enter one or more word and the php script should return all the row where all those words are include in any column.
Suppose a table like this:
|car_id|make|model|year|plate|
+----------------------------+
| 1 |Audi|A4 |2010|AAAAA|
| 2 |Audi|A4 |2012|AAAAB|
| 3 |Audi|Q5 |2010|AAAAC|
+----------------------------+
If a user enter "Aud", he get the 3 rows. If it enter "2010 Audi", he get row 1 and 3, and if he enter "Aud q5 2010", he get only row 3.
What I have done.
If the input as only 1 term, i can build a query like
SELECT * FROM car WHERE make LIKE '%term%' OR model like '%term%' OR year like '%term%'
If the user enter 2 terms, I have to create this query instead (even don't consider the plate column)
SELECT * FROM car WHERE
(make LIKE '%term%' AND model LIKE '%term2%')
OR (make LIKE '%term2%' AND model LIKE '%term%')
OR (make LIKE '%term%' AND year LIKE '%term2%')
OR (make LIKE '%term1%' AND year LIKE '%term%')
OR (model LIKE '%term%' AND year LIKE '%term%')
OR (model LIKE '%term2%' AND year LIKE '%term1%')
If a user enter 3 terms, the query get exponentialy more complexe.
I read about MATCH keyword but some column are not text, like year in this exemple.
What is the correct way to do this kind of search? Should I change database schema? Concat all searchable columns into a string and do some regex,
Thank you.
Create an extra column, all. Have it contain the CONCAT_WS(' ', ...) of all the columns you need to search on.
Create a FULLTEXT(all) index on that column.
Construct the query with just one clause:
WHERE MATCH(all) AGAINST("+Audi +q5 +2010" IN BOOLEAN MODE)
Issues:
FULLTEXT has a minimum word length; either change that (alas, it is a global setting) or deal with short "words" differently. If, say, the min word len is 3, then remove th '+' from before 'q5' in the AGAINST string. Otherwise, InnoDB will find no rows.
Similarly deal with "stop words". Or remove the stop list.
Deal with hyphenated, etc, words in some way.
It may help to do ORDER BY MATCH ... LIMIT 20 to (1) give some preference to the oddball cases, and (2) limit the output when the user does not specify enough.
Or you might want to play fair and do ORDER BY RAND() LIMIT 20.
If you are using 5.7 or MariaDB, a "generated" column may be useful.
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 am wondering if it's possible to search through a MySQL field where the field may have something like this:
test - hello
but you have in a string from a user
test: hello
Obviously it's easy on PHP-side to strip the string of any special characters like that, but is it possible to search through MySQL rows and ignore special characters?
Another unique solution is to put wildcards in between each word. As long as the search phrase does not have special characters in it, the correct results will be returned while ignoring any special characters in the results.
For example...
SELECT *
FROM myTable
WHERE somefield LIKE '%test%hello%'
It could be possible if you find and replace all such special character and spaces from user input also column,
i.e.
select * from tablename where replace(replace(columnname,' ',''),':',''),'-','')=replace(replace([USER INPUT],' ',''),':',''),'-','');
You can sort of "ignore" special characters, whitespace, etc. by using the SOUNDEX() function:
mysql> select soundex('test - hello'), soundex('test: hello');
+-------------------------+------------------------+
| soundex('test - hello') | soundex('test: hello') |
+-------------------------+------------------------+
| T234 | T234 |
+-------------------------+------------------------+
So you can search your data like this:
SELECT ...
FROM MyTable
WHERE SOUNDEX(somefield) = SOUNDEX('test: hello');
This won't be indexable at all, so it'll be forced to do a table-scan. If you use MySQL 5.7, you could add a virtual column for the soundex expression, and index that virtual column. That would help performance a lot.
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'm looking for a way to compare database values against a given query using MySql
(in oppose of searching the query in the db)
I will elaborate:
I have a table that holds comma separated keywords and a result for each block of keywords
for example :
col 1 col 2
Mercedes,BMW,Subaru car
Marlboro,Winston cigarette
today im taking the user query (for example - Marlboroligt)
as you can see if i will search for the value 'Marlboroligt' in the db i will get no results.
for that matter i want to search 'Marlboro' from the db inside the query and return 'cigarette'
Hope my explanation is sufficient and that this is actually possible :-).
Normalization will help you the most. Otherwise, search in comma delimited fields is discussed here:
Select all where field contains string separated by comma
...and to search 'Marlboroligt' instead of 'Marlboro Light', you can try looking into the LEVENSHTEIN function, or maybe the Soundex encoding (which looks like too little bang for too large a buck, but then again, maybe...).
I see the following possible solutions:
setup a keyword-search engine like Sphinx and use it to search keywords in your db
normalize your db - col1 must contain the only keyword
use like patterns
select col2 from mytable where col1 like "%Marlboro%"
like slows down your application and can have substring-related issues.