There is a table(Course Interests) which has all the values in one cell. But those values are just ids and I want to join them with another table(Course) so I can know their names.
Course Interests:
MemberID MemberName CoursesInterested
-------------- --------------------- --------------
1 Al 1,4,5,6
2 A2 3,5,6
Course Table:
CourseId Course
-------------- ---------------------
1 MBA
2 Languages
3 English
4 French
5 Fashion
6 IT
Desired Output:
MemberID MemberName CoursesInterested
-------------- --------------------- --------------
1 Al MBA,French,Fashion,IT
2 A2 English,Fashion,IT
I would like to do a SQL query in MySql that can help me to extract the desired output. I know how to do it in the opposite way(join values to one cell), but I've struggling on seek a way to separate the ids and do a cross-join into another table.
I'll appreciate any help from the community. Thanks
Use FIND_IN_SET to search for something in a comma-delimited list.
SELECT i.MemberID, i.MemberName, GROUP_CONCAT(c.Course) AS CoursesInterested
FROM CourseInterests AS i
JOIN Course AS c ON FIND_IN_SET(c.CourseId, i.CoursesInterested)
However, it would be better to create a relation table instead of storing the courses in a single column. This type of join cannot be optimized using an index, so it will be expensive for a large table.
Try this Out:
SELECT MemberID,MemberName,Group_Concat(C.Course) from
(
SELECT MemberID,MemberName,SUBSTRING_INDEX(SUBSTRING_INDEX(t.CoursesInterested, ',', n.n), ',', -1) value
FROM Table1 t CROSS JOIN
(
SELECT a.N + b.N * 10 + 1 n
FROM
(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) a
,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) b
ORDER BY n
) n
WHERE n.n <= 1 + (LENGTH(t.CoursesInterested) - LENGTH(REPLACE(t.CoursesInterested, ',', '')))
ORDER BY MemberID,value
) T JOIN course C ON T.value = C.CourseId
Group By MemberID,MemberName
Fiddle Demo
Output:
MemberID MemberName CoursesInterested
-------------- --------------------- --------------
1 Al MBA,French,Fashion,IT
2 A2 English,Fashion,IT
Related
This question already has answers here:
Search with comma-separated value mysql
(1 answer)
MySql PHP select count of distinct values from comma separated data (tags)
(5 answers)
Closed 4 years ago.
I have a table that stores data like:
userid books
ym0001 dictionary,textbooks,notebooks
ym0002 textbooks,dictionary
I want to count number of times each book occurs. I want my result to be in this format.
books Counts
dictionary 2
notebooks 1
textbooks 2
This is mysql. Please help
The following approach builds a result of 1000 integers, then uses those integers (n) to locate segments within the comma seperated string, and for each segment it creates a new row so that the derived table looks like this:
userid | book
:----- | :---------
ym0001 | dictionary
ym0002 | textbooks
ym0001 | textbooks
ym0002 | dictionary
ym0001 | notebooks
Once that exists it is a simple matter of grouping by book to arrive at the counts.
select
book, count(*) Counts
from (
select
t.userid
, SUBSTRING_INDEX(SUBSTRING_INDEX(t.books, ',', numbers.n), ',', -1) book
from (
select #rownum:=#rownum+1 AS n
from
(
select 0 union all select 1 union all select 2 union all select 3
union all select 4 union all select 5 union all select 6
union all select 7 union all select 8 union all select 9
) a
cross join (
select 0 union all select 1 union all select 2 union all select 3
union all select 4 union all select 5 union all select 6
union all select 7 union all select 8 union all select 9
) b
cross join (
select 0 union all select 1 union all select 2 union all select 3
union all select 4 union all select 5 union all select 6
union all select 7 union all select 8 union all select 9
) c
cross join (select #rownum:=0) r
) numbers
inner join mytable t
on CHAR_LENGTH(t.books)
-CHAR_LENGTH(REPLACE(t.books, ',', '')) >= numbers.n-1
) d
group by
book
order by
book
book | Counts
:--------- | -----:
dictionary | 2
notebooks | 1
textbooks | 2
If you already have a table of numbers, use that instead.
the cross joins of a b and c dynamically produce 1000 rows, if you need more add further cross joins similar to c. i.e. the number of numbers should exceed the maximum length of your comma seperated data
db<>fiddle here
I have a table in mysql which looks like below.
id cust_id date data
1 1 1/1/2018 a b c d e f g
2 1 2/1/2018 h I j k l m n
Here in this example data column is having huge data seperated by space like a b c d, I would like to show case as in row like below
id cust_id date data
1 1 1/1/2018 a
1 1 1/1/2018 b
1 1 1/1/2018 c
1 1 1/1/2018 d
2 2 2/1/2018 h
2 2 2/1/2018 i
2 2 2/1/2018 j
2 2 2/1/2018 k
I have checked few option like using unpivot function, but unable to achieve my output.
Thanks in advance !!
select
tablename.id,
tablename.date
,SUBSTRING_INDEX(SUBSTRING_INDEX(tablename.data, ' ', numbers.n), ' ', -1) name
from
(
SELECT #row := #row + 1 as n FROM
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t,
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t1,
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t2,
(SELECT #row:=0) r
) numbers INNER JOIN Table1 tablename
on CHAR_LENGTH(tablename.data)
-CHAR_LENGTH(REPLACE(tablename.data, ' ', ''))>=numbers.n-1
order by
id, n
Check link for output
http://sqlfiddle.com/#!9/fa0dcb/1
EXPLANATION:
First go through the inner query i.e.
select 0
union all
select 1
union all
select 3
union all
select 4
union all
select 5
union all
select 6
union all
select 6
union all
select 7
union all
select 8
union all
select 9
This will generate a table of 10 rows with 10 numbers.
Now the other query :
SELECT #row := #row + 1 as n FROM
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t,
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t1
Since above query is generating row numbers from below table 't' and table 't1' which is separated by ',' means that they are producing Cartesian product of their total rows.
For example: t have 10 rows and t1 also have 10 rows so, there Cartesian product produces 100 rows. So #row variable incremented 100 times and gives 100 rows of 100 numbers from 1 to 100.
The below query:
SUBSTRING_INDEX(SUBSTRING_INDEX(tablename.data, ' ', numbers.n), ' ', -1)
this one will take "a b c d e f g h" one by one.
For example:
take numbers.n = 1
then inner substring_index will find index of first space and will return string before that index i.e. 'a'
and then outer substring_index will find the space from the end of the resulting string and will give the last character from the string i.e. 'a'.
Now if you
take numbers.n = 2
then inner substring_index will find index of first space and will return string before that index i.e. 'a b'
and then outer substring_index will find the space from the end of the resulting string and will give the last character from the string i.e. 'b'
Always try to breakdown the query like this and you will able to understand the query in simpler way.
My database is like
Name | IC | Item
--------------------------
lee | xxx | pear,bear
--------------------------
ron | xxx | apple,dog
what should I do to retrieve the 4 values contained in the column "Item" and then separate them?
Do you have only two items separated by comma in Item? Or it may vary?
LE: you can use this SQL split comma separated row
LLE: just played around with that and this what I've done:
create table myTable(name varchar(7), ic varchar(7), item varchar(200));
insert into myTable(name,ic,item) values ('lee','xxx','pear,bear');
insert into myTable(name,ic,item) values ('ron','xxx','apple,dog');
insert into myTable(name,ic,item) values ('a','xxx','gamma');
insert into myTable(name,ic,item) values ('b','xxx','a,b,c,d');
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(t.item, ',', n.n), ',', -1) value
FROM myTable t CROSS JOIN
(
SELECT a.N + b.N * 10 + 1 n
FROM
(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) a
,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) b
ORDER BY n
) n
WHERE n.n <= 1 + (LENGTH(t.item) - LENGTH(REPLACE(t.item, ',', '')))
ORDER BY value;
I have 2 tables as follows:-
Products
Product_name | category_id
Nutella | 1,2
Milk | 3,4
Categories
cat_id | name
1 | dessert
2 | chocolate
3 | dairy
4 | milk
I am using datatable with server side processing using SSP library to display the products table.
I need to make join statement that get me the categories for each product since the category column contains comma separated multiple values!
Is there anyway I can do it using MYSQL?
EDIT
Expected output
Product_name | category_id
Nutella | dessert,chocolate
Milk | diary,milk
Assuming as SQL Server, First, You can use the CTE to get rows from comma separated categories ids into rows, then using INNER JOIN on cat_id, you can get the desired result.
SEE DEMO SQL Server
;WITH CTEProduct (Product_name,category_id)
AS
(
SELECT A.Product_name,
Split.a.value('.', 'VARCHAR(100)') AS category_id
FROM
(
SELECT Product_name,
CAST ('<M>' + REPLACE(category_id, ',', '</M><M>') + '</M>' AS XML) AS Data
FROM Products
) AS A CROSS APPLY Data.nodes ('/M') AS Split(a)
)
Select CTEProduct.category_id,CTEProduct.Product_name,Categories.name
From CTEProduct
INNER JOIN Categories ON CTEProduct.category_id = Categories.cat_id
EDIT:- For MYSQL, we have to follow the same approach, convert comma separated string to multiple rows then INNER JOIN. I does not know much about How to separated comma separated string to rows in MYSQL so Refer Here. I utilized the same answer here.
SEE DEMO MYSQL
Select tablename.Product_name,GROUP_CONCAT(Categories.name) name
From (
SELECT Product_name,SUBSTRING_INDEX(SUBSTRING_INDEX(t.category_id, ',', n.n), ',', -1) category_id
FROM Products t CROSS JOIN
(
SELECT a.N + b.N * 10 + 1 n
FROM
(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) a
,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) b
ORDER BY n
) n
WHERE n.n <= 1 + (LENGTH(t.category_id) - LENGTH(REPLACE(t.category_id, ',', '')))
) tablename
INNER JOIN Categories ON tablename.category_id = Categories.cat_id
GROUP BY tablename.Product_name;
In MySQL, given the following table where Tags is a column that contains comma separated strings
Id Name Salary Tags
----------------------------
1 James 5000 Sales, Marketing
2 John 4000 Sales, Finance
3 Sarah 3000 HR, Marketing, Finance
How could we get sum(Salary) for each word/tag in Tags? so the result would look like this?
Tag TotalSalary
------------------------
Sales 9000
Marketing 8000
Finance 7000
HR 3000
Any help would be very appreciated. Thank you!
While I'd highly recommend normalizing your data structure and not store comma delimited lists, here's one handy approach utilizing a "numbers" table:
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(tags, ',', n.n), ',', -1) value, sum(salary)
FROM tags CROSS JOIN
(
SELECT a.N + b.N * 10 + 1 n
FROM
(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) a
,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) b
ORDER BY n
) n
WHERE n.n <= 1 + (LENGTH(tags) - LENGTH(REPLACE(tags, ',', '')))
GROUP BY SUBSTRING_INDEX(SUBSTRING_INDEX(tags, ',', n.n), ',', -1)
SQL Fiddle Demo
This leverages substring_index and can support up to 100 delimited items - easy to adjust as needed. I've used this approach several times which works quite well -- I first saw it used in this post.