Search using comma separated string - php

So I think I completely misunderstood how FIND_IN_SET work
SELECT
u.*, p.*
FROM
users u
INNER JOIN profiles p ON p.user_id = u.id
WHERE
FIND_IN_SET('1,4,7', p.fruits)
This is not working as I thought it would.
1,4,7 represent the fruits selected by the user to search
p.fruits can look something like this 1,2,3,4,5,6,7 or 5,6,7 or 1,6,7 etc
Basically I want to find the records if any of the values in the first argument match any of the values in the second argument.
Is this possible?

if your p.fruits column is a varchar (which is not ideal for this situation, but if it is so) your query will be like
where … ( concat(',', p.fruits , ‘,’) like ‘%,1,%’
or concat(',', p.fruits , ‘,’) like ‘%,4,%’ or concat(',',p.fruits , ‘,’) like ‘%,7,%’ ) ...
this won't be good for indexes since concatenation will disable usage of indexes ..
better solution would be turn the column into a set and do the query like Michael's above ..
or you can create a new table called user_fruits(fk_user_id int, fruit_id int) and create unique index on both fields and do the search in user_fruits table

Use FIELD instead of that.
FIELD(p.fruits, 1,4,7)
You should refer to this article:
10 things in MySQL (that won’t work as expected)

Related

FIND_IN_SET with like clause mysql

I have a MySQL table where I am using comma separated values like:
user_name books
abc PHP,Java
xyz Net,Shift,PHP
I can handle comma-separated value searching using the FIND_IN_SET function of MySQL.
Now books names are auto suggested means if any one search with keyword "J" , system should search and match the word Java and give result of user "abc".
I tried to use like clause with FIND_IN_SET but it's not working.
Does anyone have any suggestions?
Not a clean solution but you can use something like this:
SELECT * FROM `library` WHERE `books` LIKE 'J%' OR `books` LIKE '%,J%'

Get an array of all columns starting with the same characters.

This is quite difficult to explain in the title, so I'll do my best here. Basically I have a column in a MySQL products table that contains rows like:
FEL10
FEL20
FEL30
PRO05
PRO07
PRO08
VAI12
VAI13
VAI14
These are the categories ("FEL","PRO","VAI") and a identification number of my products ("10", "20" and so on). I need an SQL select query that creates me a textual array like:
FEL*
PRO*
VAI*
With this array I need to create a listbox, that allows me to choose a category (regardless of the identification number). Once I choose a category, let's say PRO*, I will need to do the reverse action: print all the products info related to PRO05, PRO07 and PRO08.
How do you think you can achieve this? I have been trying using the DISTINCT statement but I need to filter only the first characters, otherwise it will be useless. I also tried the SUBSTRING() and LEFT() functions, but they seem not to be working (I get an SQL Syntax error).
--
Thanks for your help as always
What is wrong with?
SELECT distinct left(col, 3) as category FROM `table1`
MySQL LIKE to the resque:
SELECT col1 FROM table1 WHERE col1 LIKE 'FEL%';
This way you have to add all cases using OR.
Alternative - REGEXP:
SELECT col1 FROM table1 WHERE col1 REGEXP '(FEL|PRO|VAI).*'
Then it's just a matter of writing proper regex.
I would use extra col to group your items - to avoid such selecting altogether (which should be quite expensive on bigger dataset).
https://dev.mysql.com/doc/refman/5.1/en/regexp.html#operator_regexp
To get the list of the 3-letter codes use:
select distinct left(combicode, 3)
from mytable;
When a user selects one of the values use this to get all matching entries:
select *
from mytable
where combicode like concat(#category, '%');
(Aside from that: It's a bad idea to have concatenated values in one column. Why not have one column for the category and another for the product code? Then there would be no problem at all.)

Filter MySQL comma separated field

In my table there is field called agency_ids. It will have comma separated string values like below. a0001, a0002. One or may agent ids can contain per record.
Now i need to search the table using given agency id.
Ex - if i give a1235 it should return both rows showed above. If i give a1234 it should return only row with a1234.
How can i do it ? I tried agency_ids IN ('a1234') and FIND_IN_SET but it didn't work.
Complete query -
SELECT ov.*,c.name as company_name
FROM (SELECT v.vacancy_id,v.company_id,v.designation,v.job_ref_number
FROM `t2o_vacancies` AS v
WHERE `opening_date` <= '2014-01-27'
AND `closing_date` >= '2014-01-27'
AND posting_type= 'Agency'
AND agency_ids IN ('a1234')
ORDER BY v.opening_date DESC ) AS ov
LEFT JOIN t2o_companies AS c ON ov.company_id = c.id
Try using like
and agency_ids like '%a1235%'
instead of using IN
AND agency_ids IN ('a1234')
in will allow you to specify multiple values, but it will not look at a1234,a1235 as two different values.
How about using LIKE operator instead of IN?
SELECT ov.*,c.name as company_name
FROM (SELECT v.vacancy_id,v.company_id,v.designation,v.job_ref_number
FROM `t2o_vacancies` AS v
WHERE `opening_date` <= '2014-01-27'
AND `closing_date` >= '2014-01-27'
AND posting_type= 'Agency'
AND agency_ids LIKE '%a1234%'
ORDER BY v.opening_date DESC ) AS ov
LEFT JOIN t2o_companies AS c ON ov.company_id = c.id
you can sure use where agency_ids like %a1235% yet this might not be the best approach.
have you considered using relational database ?
if you can add another table to your schema you can do
table t2o_companies
normal structure......
table t2o_vacancies
normal structure......
table t2o_companies_t2o_vacancies
id company_id vacancie_id
i'm not sure whats your current schema is, yet if you gona need to fetch row using agency_id then i would have a join table rather than just saving them in 1 field with comma separation.
yet if you dont want to change schema, then just dont forget to index agency_ids for faster searching.

MySQL: Find similar repeated entries

Given my table
id | name
01| Test Name
02| Name Test
03| Another name
...
...
nn| Test string
I'd like to do the following, for each entry, read the first word, until a space, so in this example i would read Test, then, find all similar entries which contain Test anywhere on the string, then continue with Name, Another, and so on.
I don't want to do this manually, as I'll have to make a lot of queries, the idea is the data is imported from an old excel spreadsheet and the client wants to get repeated names, so Test Name, Test Something Name and Name Test are potential similar names.
You want to run a query, select all the names, return that to php, then loop through it, parse the string into separate words, and run a query with a fulltext index.
here's something to get you started.
http://www.databasejournal.com/sqletc/article.php/1578331/Using-Fulltext-Indexes-in-MySQL---Part-1.htm
Here's my db solution:
SELECT *
FROM princess a
INNER JOIN (SELECT
DISTINCT CASE
WHEN name LIKE '% %'
THEN SUBSTR(name, 1, LOCATE(' ', name) - 1)
ELSE name
END AS 'name'
FROM princess) b ON a.name LIKE CONCAT('%', b.name ,'%')
This will find the DISTINCT names (before a space) and then JOIN to the original table using LIKE.
You may also consider using INSTR(a.name, b.name) in place of b.name LIKE CONCAT('%', a.name ,'%') depending on how your EXPLAIN looks.
There are a ton of examples of how to split a string into multiple rows in MySQL, e.g. this one.
After that, you can find the exact matches easily. If you want non-exact matches, check out SOUNDEX()

Comma separated values in MySQL "IN" clause

I have a column in one of my table where I store multiple ids seperated by comma's.
Is there a way in which I can use this column's value in the "IN" clause of a query.
The column(city) has values like 6,7,8,16,21,2
I need to use as
select * from table where e_ID in (Select city from locations where e_Id=?)
I am satisfied with Crozin's answer, but I am open to suggestions, views and options.
Feel free to share your views.
Building on the FIND_IN_SET() example from #Jeremy Smith, you can do it with a join so you don't have to run a subquery.
SELECT * FROM table t
JOIN locations l ON FIND_IN_SET(t.e_ID, l.city) > 0
WHERE l.e_ID = ?
This is known to perform very poorly, since it has to do table-scans, evaluating the FIND_IN_SET() function for every combination of rows in table and locations. It cannot make use of an index, and there's no way to improve it.
I know you said you are trying to make the best of a bad database design, but you must understand just how drastically bad this is.
Explanation: Suppose I were to ask you to look up everyone in a telephone book whose first, middle, or last initial is "J." There's no way the sorted order of the book helps in this case, since you have to scan every single page anyway.
The LIKE solution given by #fthiella has a similar problem with regards to performance. It cannot be indexed.
Also see my answer to Is storing a delimited list in a database column really that bad? for other pitfalls of this way of storing denormalized data.
If you can create a supplementary table to store an index, you can map the locations to each entry in the city list:
CREATE TABLE location2city (
location INT,
city INT,
PRIMARY KEY (location, city)
);
Assuming you have a lookup table for all possible cities (not just those mentioned in the table) you can bear the inefficiency one time to produce the mapping:
INSERT INTO location2city (location, city)
SELECT l.e_ID, c.e_ID FROM cities c JOIN locations l
ON FIND_IN_SET(c.e_ID, l.city) > 0;
Now you can run a much more efficient query to find entries in your table:
SELECT * FROM location2city l
JOIN table t ON t.e_ID = l.city
WHERE l.e_ID = ?;
This can make use of an index. Now you just need to take care that any INSERT/UPDATE/DELETE of rows in locations also inserts the corresponding mapping rows in location2city.
From MySQL's point of view you're not storing multiple ids separated by comma - you're storing a text value, which has the exact same meaing as "Hello World" or "I like cakes!" - i.e. it doesn't have any meaing.
What you have to do is to create a separated table that will link two objects from the database together. Read more about many-to-many or one-to-many (depending on your requirements) relationships in SQL-based databases.
Rather than use IN on your query, use FIND_IN_SET (docs):
SELECT * FROM table
WHERE 0 < FIND_IN_SET(e_ID, (
SELECT city FROM locations WHERE e_ID=?))
The usual caveats about first form normalization apply (the database shouldn't store multiple values in a single column), but if you're stuck with it, then the above statement should help.
This does not use IN clause, but it should do what you need:
Select *
from table
where
CONCAT(',', (Select city from locations where e_Id=?), ',')
LIKE
CONCAT('%,', e_ID, ',%')
but you have to make sure that e_ID does not contain any commas or any jolly character.
e.g.
CONCAT(',', '6,7,8,16,21,2', ',') returns ',6,7,8,16,21,2,'
e_ID=1 --> ',6,7,8,16,21,2,' LIKE '%,1,%' ? FALSE
e_ID=6 --> ',6,7,8,16,21,2,' LIKE '%,6,%' ? TRUE
e_ID=21 --> ',6,7,8,16,21,2,' LIKE '%,21,%' ? TRUE
e_ID=2 --> ',6,7,8,16,21,2,' LIKE '%,2,%' ? TRUE
e_ID=3 --> ',6,7,8,16,21,2,' LIKE '%,3,%' ? FALSE
etc.
Don't know if this is what you want to accomplish. With MySQL there is feature to concatenate values from a group GROUP_CONCAT
You can try something like this:
select * from table where e_ID in (Select GROUP_CONCAT(city SEPARATOR ',') from locations where e_Id=?)
this one in for oracle ..here string concatenation is done by wm_concat
select * from table where e_ID in (Select wm_concat(city) from locations where e_Id=?)
yes i agree with raheel shan .. in order put this "in" clause we need to make that column into row below code one do that job.
select * from table where to_char(e_ID)
in (
select substr(city,instr(city,',',1,rownum)+1,instr(city,',',1,rownum+1)-instr(city,',',1,rownum)-1) from
(
select ','||WM_CONCAT(city)||',' city,length(WM_CONCAT(city))-length(replace(WM_CONCAT(city),','))+1 CNT from locations where e_Id=? ) TST
,ALL_OBJECTS OBJ where TST.CNT>=rownum
) ;
you should use
FIND_IN_SET Returns position of value in string of comma-separated values
mysql> SELECT FIND_IN_SET('b','a,b,c,d');
-> 2
You need to "SPLIT" the city column values. It will be like:
SELECT *
FROM table
WHERE e_ID IN (SELECT TO_NUMBER(
SPLIT_STR(city /*string*/
, ',' /*delimiter*/
, 1 /*start_position*/
)
)
FROM locations);
You can read more about the MySQL split_str function here: http://blog.fedecarg.com/2009/02/22/mysql-split-string-function/
Also, I have used the TO_NUMBER function of Oracle here. Please replace it with a proper MySQL function.
IN takes rows so taking comma seperated column for search will not do what you want but if you provide data like this ('1','2','3') this will work but you can not save data like this in your field whatever you insert in the column it will take the whole thing as a string.
You can create a prepared statement dynamically like this
set #sql = concat('select * from city where city_id in (',
(select cities from location where location_id = 3),
')');
prepare in_stmt from #sql;
execute in_stmt;
deallocate prepare in_stmt;
Ref: Use a comma-separated string in an IN () in MySQL
Recently I faced the same problem and this is how I resolved it.
It worked for me, hope this is what you were looking for.
select * from table_name t where (select (CONCAT(',',(Select city from locations l where l.e_Id=?),',')) as city_string) LIKE CONCAT('%,',t.e_ID,',%');
Example: It will look like this
select * from table_name t where ',6,7,8,16,21,2,' LIKE '%,2,%';

Categories