Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comma separated values in MySQL "IN" clause

Tags:

sql

php

mysql

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.

like image 804
Sashi Kant Avatar asked May 07 '12 10:05

Sashi Kant


People also ask

Where clause with comma separated values in MySQL?

To perform where clause on comma separated string/values, MySQL has an inbuilt function called FIND_IN_SET which will search for values within a comma separated values. You can also use IN operator to achieve the same but there are some limitations with IN operator which I will show below.

Can we store comma separated values in MySQL?

You never store comma separated arrays in a database - each entry in the comma separated array needs to be stored in its own row in a table in the database.

How use comma separated values in SQL query?

Now for the perfect comma separated value we must remove the first comma in the above query result. This can be done using "STUFF" or the SUBSTRING function. STUFF deletes a specified length of characters from the given string and inserts another set of characters at a specified starting point.


2 Answers

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.

like image 126
Bill Karwin Avatar answered Oct 18 '22 10:10

Bill Karwin


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.

like image 29
Crozin Avatar answered Oct 18 '22 10:10

Crozin