Search a string in multiple fields of a table - php

I have a table User which has the fields (id, first_name, middle_name, last_name).
I want to write a query to find a user by his name. The name may be first name, middle name or last name.
$sql = "SELECT * FROM user
WHERE first_name like '%$name%' OR
middle_name like '%$name%' OR
last_name like '%$name%'";
Is it efficient query?
(Leave the security issue for the time being.)

Alter table and add composite Fulltext index on First_name,second_name,last_name then use this query
select *
from table_name
where match (`First_name`,`second_name`,`last_name`) against('name')
It's pretty much faster then your query.

As soon as you have a LIKE '%something%' in your WHERE clause, you force a table scan. So yes, it is inefficient, but one or three LIKE statements will make little difference.
The table scan is the big performance hit.
Consider looking at MySQL's Full Text Search capability. It is designed to answer this type of query much more efficiently.

If you need to search for a pattern in more than one fields, and if you have the permission to change table schema, i would suggest implementing FULL-TEXT SEARCH.
Hope it helps :)

Related

we need to retrieve all the rows from mysql. And table has only a single column e.g name.Which approach is better?

Which of below query will be better to use if table has single column? Please also provide technical justification.
select * from table
or
select `name` from table
Speed/execution be the same. Just because of future table changes (and clarity of the message) you should use second option.
* is just placeholder for all; though there is no difference, because engine treats it like name in that case, but if some day you change table rows (add something, for example surname) it would be best choice, to use just name in select statement due to avoid future source-code changes.

Search entire table for a keyword

I have a trivial question. Im using PHP+MySQL managing a huge DB
I want to search in a entire table a keyword I write in a input.
The problem is that the main table have +100 columns, so I had to write the php query manually
[...]
$sql="select *
from db
where ID LIKE '%".$q."%' or USER_ID LIKE '%".$q."%' or Phone_ID LIKE '%".$q."%' or
Fax_ID LIKE '%".$q."%' or email_ID LIKE '%".$q."%' or [...]
And this is a chaos when I modify a column, or add/remove...
Exist any other way to make this search? If not, I tought about create a separate PHP function, that obtains all column header names, and create an auto-fill function inside.
I tried to look for info with no success
https://stackoverflow.com/search?q=search+entire+table
Unfortunately there isnt any simple way to do this.
One option is to select all columns in table, fetch them as array and iterate over them and build your WHERE clause.
select column_name from information_schema.columns
where table_name = 'TableName'
This will make whole script slower, if you want to go this way i would recommend you to use some caching.
You could get the column info for the 'main table' using info from the information schema. Here are some methods for using MySQL. Here is how to do it using PHP.
You can do a SHOW COLUMNS on the table, then loop over the Field to get all the column names in the table, at least that way you don't have a hand-coded mess to deal with.

How to properly construct a MySQL search string with PHP?

I am trying to understand what is the best way to construct a query string with php when there are multiple columns I want it to look for.
For example the database has id, name, email, date.
And I have a search input field on a page which when submitted, I want it to search based on the input field against the above mentioned columns. Best what is the best way/practice to do that?
I have the following so far but it seems like it is a "dumb" search.
"SELECT * FROM Table WHERE id LIKE '$search%' || name LIKE '$search%' || email LIKE '$search%' || date LIKE '$search%'";
Well this sort of works but I feel there has to be a better way and a more appropriate smarter method.
Thanks...
You cannot make mysql use index properly when you are querying multiple columns and not using AND (you are using OR)
There is always need to optimize your query strategy, always people think the data is small,
why bother to spend effort to optimize ... but the truth is you don't know when your data will grow
For your query, if you want to stick to LIKE,
then you need to build 4 indexes on the 4 columns,
alter table Table add index on(id);
alter table Table add index on(name);
alter table Table add index on(email);
alter table Table add index on(date);
And change the query to :-
SELECT * FROM Table WHERE id LIKE '$search%'
union distinct
SELECT * FROM Table where name LIKE '$search%'
union distinct
SELECT * FROM Table where email LIKE '$search%'
union distinct
SELECT * FROM Table where date LIKE '$search%'
What is Union ?
Off-topic issue :-
you did not escape for user input, it could lead to SQL injection
is meaningless to search on ID when the input could be anything
same go for date
I found myself asking the same question a few years back. For the kind of functionality you are looking for, the most efficient way is full text search. Of course it come at the cost of space. I did not find any other way of implementing this efficiently. sorry i do not know if fts is supported in mysql.

MySQL Search optimisation for better performance

I have an array with a list of keywords,
$arr = array('london','england','football',...);
The array could have Nth keywords.
I need to use this on a sql query but i dont want to do too many repetitions like this.
select * from t1 where title LIKE('%$arr[0]%') OR title LIKE('%$arr[1]%') [...]
just need a better solution as each keyword filters out the records.
thnx
One solution would be to create a lookup table that is populated with the rowid and keywordid whenever a row is created or changed.
Then you can skip all the LIKE and get much more performance.
A trigger on insert and update should work but it will cost a little more performance on insert and update.
You would just use
SELECT * FROM t1 WHERE id in (SELECT id FROM lookup WHERE keywordid IN ())
And if the keywords are many you could use a sub query more to get the keyword id's or if fewer use a cached lookup structure directly in code, dictionary or likewise.
http://www.webdevelopersnotes.com/tutorials/sql/tutorial_mysql_in_and_between.php3
I'm unsure whether you wanted to optimize the actual query itself or the means to insert keywords into the query.
If it's the latter, then what comes to mind quickly is:
$query = "SELECT * FROM t1 WHERE title";
foreach($arr as $keyword)
{
$stack[] = " LIKE '%$keyword%' ";
}
$query .= implode(' OR title ', $stack);
If you want to avoid full table scans based on keywords, that requires a different topic in itself with more explanation at your end.
Depending on the kind (and amount) of searches you'll be doing, you might need to consider using something else than pure-MySQL for that.
MySQL by itself is not quite well-suited when it comes to fulltext search :
Using like '%...%' will result in bad performances (scanning all the lines of your table)
Using a FULLTEXT index means using MyISAM as storage engine.
If you need to do a lot of searches, it might become more interesting to invest in a solution dedicated to indexing/searching through text, like Solr, or Sphinx.

Keyword search using PHP MySql?

I have title (varchar), description (text), keywords (varchar) fields in my mysql table.
I kept keywords field as I thought I would be searching in this field only. But I now require to search among all three fields. so for keywords "word1 word2 word3", my query becomes
SELECT * FROM myTable
WHERE (
name LIKE '%word1%' OR description LIKE '%word1%' OR keywords LIKE '%word1%'
OR name LIKE '%word2%' OR description LIKE '%word2%' OR keywords LIKE '%word2%'
OR name LIKE '%word3%' OR description LIKE '%word3%' OR keywords LIKE '%word3%')
AND status = 'live'
Looks a bit messy but this works. But now I need to implement synonym search. so for a given word assuming there are a few synonyms available this query becomes more messy as I loop through all of the words. As the requirements are getting clearer, I will need to join this myTable to some other tables as well.
So
Do you think the above way is messy and will cause problems as the data grow?
How can I avoid above mess? Is there any cleaner solution I can go by? Any example will help me.
Is there any other method/technique you can recommend to me?
With thanks
EDIT
#Peter Stuifzand suggested me that I could create one search_index table and store all 3 fields (title,keyword,desc) info on that and do full text search. I understand that additionally this table will include reference to myTable primary key as well.
But my advanced search may include joining mytable with Category table, geographic_location table (for searching within 10, 20 miles etc), filtering by someother criteria and of course, sorting of search results. Do you think using mysql fulltext will not slow it down?
When your queries are getting out of hand, it's sometimes better to write parts of it in SQL and other parts in your programming language of choice.
And you could also use fulltext search for searching. You can create separate table with all fields that you want to search and add the FULLTEXT modifier.
CREATE TABLE `search_index` (
`id` INT NOT NULL,
`data` TEXT FULLTEXT,
);
SELECT `id` FROM `search_index` WHERE MATCH(`data`) AGAINST('word1 word2 word3');
One more way (sometimes it's better but it depends...)
SELECT
id, name, description, keywords
FROM
myTable
WHERE
name REGEXP '.*(word1|word2|word3).*' OR
description REGEXP '.*(word1|word2|word3).*' OR
keywords REGEXP '.*(word1|word2|word3).*'
;
PS: But MATCH(cols) AGAINST('expr') possibly is better for your case.
If at all possible, you should look into fulltext search.
Given the expanded requirements, you might want consider using apache solr (see http://lucene.apache.org/solr/) it is a faceted search engine, designed for full text searching. It has a RESTful interface that can return XML or JSON. I am using it with a few projects - works well.
The only area I see you hitting some problems is potentially with the proximity search, but with some additional logic for building the query it should work.

Categories