This question already has answers here:
Is storing a delimited list in a database column really that bad?
(10 answers)
Closed 4 years ago.
What I have with me?
A string with comma separated :
$str_states = "1,2";
I have a table with the following:
id event_name states
1 ABC 1,4,5
2 PQR 1,2,3
3 XYZ 3,4,5
What I want:
id event_name states
1 ABC 1
2 PQR 1,2
What I tried with a query:
SELECT id,event_name FROM events_table WHERE
FIND_IN_SET('1,2', states);
SELECT id,event_name FROM events_table WHERE
states IN ('51,58');
You can't really use FIND_IN_SET the way you want here. FIND_IN_SET searches for a single value against a CSV string. So, you would have to use OR here:
SELECT id, event_name
FROM events_table
WHERE FIND_IN_SET('1', inLocationId) > 0 OR FIND_IN_SET('2', inLocationId) > 0;
If your starting point for the input is 1,2, then you will have to tease apart the individual values in your app layer.
By the way, storing CSV unnormalized data in your SQL tables is bad practice. You would be better off to fix your design than to use my answer.
As a bonus, here is a more terse way to write your query using REGEXP:
SELECT id, event_name
FROM events_table
WHERE inLocationid REGEXP '[[:<:]](1|2)[[:>:]]';
But again, please fix your data model.
Related
I want to select all package_id that contain product_id 2.
In this case, package_id 1,3,5 has product_id 2
Table: product_package
package_id package_name product_id
---------------------------------------------
1 Gold 1,2,3
2 Platinum 4,5,12
3 Diamond 2,11,5
4 Titanium 3,5
5 Basic 2
I tried:
SELECT
*
FROM
product_package
WHERE product_id IN(2)
It is outputting package_id 3 and 5 only. How do I output this properly?
product_id structure is varchar(256). Should I change the structure or add Foreign keys?
We always recommend not to stored delimited columns see Is storing a delimited list in a database column really that bad?
But you can use FIND_IN_SET but this is always slow
SELECT
*
FROM
product_package
WHERE FIND_IN_SET(2,product_id)
package_id
package_name
product_id
1
Gold
1,2,3
3
Diamond
2,11,5
5
Basic
2
fiddle
First, let me explain what is happening in your query.
You have WHERE product_id IN(2), but product_id is a misnomer and should rather be product_ids, because it is multiple IDs unfortunately stored in a string. IN is made to look up a value in a list. Your list, however, only consists of one element, so you can just as well use the equality operator: WHERE product_id = 2.
What you have is WHERE string = number, so the DBMS has to convert one of the values in order to compare the two. It converts the string to a number (so '2' matches 2 and '002' matches 2, too, as it should). But your strings are not numbers. The DBMS should raise an error on '1,2,3' for instance, because '1,2,3' is not a number. MySQL, however, has a design flaw here and still converts the string, regardless. It just takes as many characters from the left as they still represent a number. '1' does, but then the comma is not considered numerical (yes, MySQL cannot deal with a thousand separator when convertings strings to numbers implicitly). So converting '1,2,3' to a number results in 1. Equally, '2,11,5' results in 2, so rather surprisingly '2,11,5' = 2 in MySQL. This is why you are getting that row.
You ask "Should I change the structure", and the answer to this is yes. So far your table doesn't comply with the first normal form and should thus not exist in a relational database. You'll want two tables instead forming the 1:n relation:
Table: package
package_id
package_name
1
Gold
2
Platinum
3
Diamond
4
Titanium
5
Basic
Table: product_package
package_id
product_id
1
1
1
2
1
3
2
4
2
5
2
12
3
2
3
11
3
5
4
3
4
5
5
2
You ask "or add Foreign keys?", and the answer is and add foreign keys. So with the changed structure you want product_package(product_id) to reference product(product_id) and product_package(package_id) to reference package(package_id).
Disregarding that you should not be storing multiple values in a single field, you can use LIKE operator to achieve what you are looking for. I'm going with assumptions:
all values are delimited with commas
all values are integers
there are no whitespaces (or any other characters besides integers and commas)
select * from product_package
where product_id like '2,%'
or product_id like '%,2,%'
or product_id like '%,2'
or product_id like '2'
Alternatively, you can use REGEXP operator:
select * from product_package
where product_id regexp '^2$|^2,.+|.+,2,.+|.+,2'
References:
MySQL LIKE
MySQL REGEXP
This question already has answers here:
Is storing a delimited list in a database column really that bad?
(10 answers)
Closed 2 years ago.
genreTable:
id
genre
1
Pop
2
Rock
3
Electro
songTable:
id
name
genre
1
Song1
1
2
Song2
1,2
3
Song3
2,3
Problem: Lets say I want to build query like:
SELECT * FROM songTable WHERE genre = '1'
It'll only return Song1
But how Do I make sure it also returns Song1, Song2
Any other suggestions regarding re-structuring the table is also accepted...
You should fix your data model! There are many reasons why your data model is broken:
Columns should only contain one value.
Numbers should be stored as numbers, not strings.
Foreign key relationships should be properly declared.
SQL has pretty bad string processing capabilities.
Sometimes, you are stuck with other people's really, really, really bad design decisions. In that case, you can use find_in_set():
select s.*
from songTable s
where find_in_set('1', genre) > 0
This question already has answers here:
Is storing a delimited list in a database column really that bad?
(10 answers)
Closed 4 years ago.
Table name: student:
id name topics
--- ---- --------
1 Test1 1,2,10,15,25
2 Test2 5,21,11,18,13
3 Test3 2,1,16,25,10
4 Test4 2
My query:
select * from student where topics like '%2%'
output: all 4 records.
Expected: But i need to get only 3 record since that id 1,3,4 topics column contains 2. 2nd record doesn't contain 2 .
You can use the function FIND_IN_SET :
select * from student where FIND_IN_SET ('2', topics)
The second record DOES contain 2.
You need to use something like this.
WHere topics=2 or topics like '2,%'or topics like '%,2' or topics like '%,2,%'
The first checks if topics is 2. THe second if 2 is the first, but there are others. THe third checks if 2 is the last, but there are some numbers before, and the forth checks if 2 is somewhere in between
Something like that might help?
SELECT * FROM student WHERE topics LIKE '2,%' OR topics LIKE '%,2,%' OR topics LIKE '%,2' OR topics= '2';
its sad that you cant use IN with LIKE.
This question already has answers here:
Find total number of results in mySQL query with offset+limit
(7 answers)
Closed 6 years ago.
I am making a pagination function, here is my case:
1 table (example)
id | title | date | details
Now, I want to retrieve two different results from this table (example)
Count all of the rows (for the total count of all the lists)
I will only show every 10 list per page.
My current code is, I have 2 separated queries for 1 and 2, so it is like 2 connections, my question is, can this be done with a single query and then retrieve both of 1 and 2 results? If so, what do I need to do? Any suggestion/s can help me!
I think,
This will help you.
Step 1: Get the all list from the table
Step 2: Then count the records
Here is the single query to perform it.
SELECT COUNT(tmp.id) as cnt, tmp.* FROM (SELECT id, title, date, details FROM tablename) tmp
This question already has answers here:
MySQL query finding values in a comma separated string
(11 answers)
Closed 7 years ago.
I have records in user table in following manner
id name address keywords
1 thompsan paris 10,20,30
2 samson paris 10,20,30
3 Nilawa paris 10,20,30
4 Nalama paris 100,30,50
5 Nalama paris 100,300,20
I need to get the users who have the keywords of 10 or 20. I have written this query:
SELECT * from User where keywords REGEXP '[[:<:]]10|20[[:>:]]'
It does not give me the expected output. It should filter for id 10 or 20 and give me the output of record 1,2,3,5. record 4 is not matching here.
Why is it not working? Is there a better way to do this?
Try this,
SELECT *
FROM user
WHERE FIND_IN_SET('10', keywords) > 0 OR
FIND_IN_SET('20', keywords) > 0
FIND_IN_SET is a builtin function with MySQL
Redesign your database so that it's actually in 1NF and you won't have to deal with these headaches not to mention the horrible performance and bugs that it's bound to bring you down the line.
Since I know that you won't do that though, there's no need to use REGEXP at all, assuming that your string in keywords is actually consistent (and if it's not then you're screwed anyway). Just use LIKE:
SELECT -- We'll list out the columns, since we NEVER use SELECT *
id,
name,
address,
keywords
FROM
User
WHERE
',' + keywords + ',' LIKE '%,10,%' OR
',' + keywords + ',' LIKE '%,20,%'