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.
Related
I would like to write an sql statement for search. Here is sample database structure.
For eg, I want to display all records with topic '13'. How can i write sql query for searching 13 from the above structure? Any suggestions?
Can i able to use WHERE Topic LIKE '%13%'? Anything wrong with this?
Try this one:
SELECT * FROM `TABLE_NAME` WHERE `Topic` LIKE "%13%";
It's better and faster to save it in a third table of many-to-many relationship.
If you want to save as per your example (single table), try to save data as eg ",10,13,15,"
always have coma before and after, thus the following sql will exclude 213 and 132 etc
select * from table_name where Topic like '%,13,%'
select * from table where find_in_set("13",topic);
or if topic is not used as a set, you could do ...
select * from table where concat(",",topic) like "%,13,%";
The 2nd isn't real elegant but I've had to do that a couple times.
Because the data isn't really normalized, I used concat to add a comma to the topic field so I could make sure the "like" comparison would pass with a comma before and after the value. I suppose we would also have to remove any unwanted spaces as well for this example, so ultimately it would end up like:
select * from TABLE where concat(",",replace(topic," ","")) like "%,13,%";
Ultimately, we have to know what to expect in the topic column to come up with a query that would always work. In the past, I've had situations where I would add values to a string field (i.e. topic) with a delimiter before and after each value like:
(1)(2)(3)(14)(15)(255)(283)
If you did something like this for the topic field, the query is simple ...
select * from table where topic like "%(13)%";
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.
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 :)
This is a bit of a difficult problem for me to word, and I may be going about it in the completely wrong way.
I'm storing a set of options in a database, where each option is its own column. The user can change the number of options, however, so I need a way of allowing PHP to always select all the options.
Let's say I have these columns: options_dialog_1, options_dialog_2, options_dialog_3, options_dialog_4
There could be a varying number of these dialog option columns, eg, another called options_dialog_5 could be added.
How do I select all the dialog option columns, based on their column name format?
I think you have a database design problem here; repeating columns like that always leads to trouble in the end. I think you need two tables, one for the user and one for the options defined something like this...
USERS
id
name
OPTIONS
id
user_id
option_dialogue_number
option_dialogue_value
That turns the columns into rows, which are rather easier to get at.
Brian's answer will really, really pay you off in longer period. But if you need something quick & ugly, you can check out the "metadata dictionary" (tables that store information about all other tables, columns etc). You could get list of columns from it with first query and use it to build the second one.
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='mytable' AND COLUMN_NAME LIKE 'options_dialog%'
Visit the manual on INFORMATION_SCHEMA for more goodies.
I am not sure I understand the problem. Are you looking for
SELECT * FROM options_table
Something like (faux SQL - wont work)
SELECT ( SELECT column_names where column_name LIKE 'options_dialog%' )
FROM options_table
sounds not feasible to me (though I am sure it's possible somehow). If you need this, either consider refactoring the database design or maybe use a bitmask to store the selected options in a single column.
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.