Converting rows records to columns in mySQL - mysql

I'm trying to convert row data to columns. Data will be extracted from different tables. I tried using PIVOTbut I'm not much successful.
Lets consider column#1 as primary key in every table.
CREATE TABLE Table_pivot_01
([SSN ID] int, [Citizen_name] varchar(5), [Company] varchar(4))
;
INSERT INTO Table_pivot_01
([SSN ID], [Citizen_name], [Company])
VALUES
(12345, 'John', 'XYZ'),
(12346, 'Tom', 'ABC'),
(12347, 'Jerry', 'QWER'),
(12348, 'Joe', 'PQR'),
(12349, 'Josh', NULL)
;
CREATE TABLE Table_pivot_02
([Serial] int, [SSN_ID] int, [Family_details] varchar(9), [Family_members_name] varchar(10))
;
INSERT INTO Table_pivot_02
([Serial], [SSN_ID], [Family_details], [Family_members_name])
VALUES
(1010, 12345, 'Spouse', 'Mari'),
(1011, 12345, 'Child - 1', 'John Jr. 1'),
(1012, 12345, 'Child - 2', 'John Jr. 2'),
(1013, 12346, 'Spouse', 'Ken'),
(1014, 12347, 'Spouse', 'Suzen'),
(1015, 12347, 'Child - 1', 'Jerry Jr.1'),
(1016, 12347, 'Child - 2', 'Jerry Jr.2'),
(1017, 12347, 'Child - 3', 'Jerry Jr.3'),
(1018, 12348, 'Child - 1', 'Joe Jr.1'),
(1019, 12348, 'Child - 2', 'Joe Jr.2'),
(1020, 12349, 'Spouse', 'Zoe'),
(1021, 12349, 'Child - 1', 'Josh Jr.1'),
(1022, 12349, 'Child - 2', 'Josh Jr.2')
;
CREATE TABLE Table_pivot_03
([Row] int, [SSN_ID] int, [Address_type] varchar(8), [Address] varchar(22), [PhoneNumber_type] varchar(6), [PhoneNumber] varchar(18))
;
INSERT INTO Table_pivot_03
([Row], [SSN_ID], [Address_type], [Address], [PhoneNumber_type], [PhoneNumber])
VALUES
(121, 12345, 'Present', 'Address_John_Present', 'Home', 'John_Home_phone'),
(122, 12345, 'Office', 'Address_John_Office', 'Office', 'John_Office_phone'),
(123, 12345, 'Perement', 'Address_John_Perement', 'Fax', 'John_FAX_phone'),
(124, 12346, 'Present', 'Address_Tom_Present', 'Home', 'Tom_Home_phone'),
(125, 12346, 'Office', 'Address_Tom_Office', 'Office', 'Tom_Office_phone'),
(126, 12347, 'Office', 'Address_Jerry_Office', 'Home', 'Jerry_Home_phone'),
(127, 12347, 'Perement', 'Address_Jerry_Perement', 'Office', 'Jerry_Office_phone'),
(128, 12348, 'Present', 'Address_Joe_Present', 'Home', 'Joe_Home_phone'),
(129, 12348, 'Office', 'Address_Joe_Office', 'Office','Joe_Office_phone'),
(130, 12348, 'Perement' , 'Address_Josh_Perement','','' ),
(131, 12349, 'Present','Address_Josh_Present','Home','Josh_Home_phone'),
(132, 12349, 'Perement', 'Address_Josh_Perement' , 'Fax' ,'Josh_FAX_phone');
Table schema : http://rextester.com/MSXK16689
The Expected Output is:
How can I build the result in effective way?

MySQL Version
You've stated that you have tried using PIVOT but MySQL doesn't have a PIVOT function. In MySQL you need to use an aggregate function along with a conditional logic statement like CASE...WHEN or something similar. You also have several tables and several different columns you need to pivot which complicates this a bit. It also seems that you have an unknown number of new columns that need to be created, which adds another layer of complexity.
If you know all of the columns you want to be displayed in the final result, then you can easily type up a version of this query to be something like:
select
p1.`SSN_ID`,
p1.Citizen_name,
p1.Company,
max(case when p2.Family_details = 'Spouse' then Family_members_name end) Spouse,
max(case when p2.Family_details = 'Child - 1' then Family_members_name end) Child1,
max(case when p2.Family_details = 'Child - 2' then Family_members_name end) Child2,
max(case when p2.Family_details = 'Child - 3' then Family_members_name end) Child3,
max(case when p2.Family_details = 'Child - 4' then Family_members_name end) Child4,
max(case when p3.Address_type = 'Present' then p3.Address end) PresentAddress,
max(case when p3.Address_type = 'Office' then p3.Address end) OfficeAddress,
max(case when p3.Address_type = 'Perement' then p3.Address end) PermAddress,
max(case when p3.PhoneNumber_type = 'Home' then p3.PhoneNumber end) HomePhone,
max(case when p3.PhoneNumber_type = 'Office' then p3.PhoneNumber end) OfficePhone,
max(case when p3.PhoneNumber_type = 'Fax' then p3.PhoneNumber end) FaxPhone
from Table_pivot_01 p1
left join Table_pivot_02 p2
on p1.`SSN_ID` = p2.`SSN_ID`
left join Table_pivot_03 p3
on p1.`SSN_ID` = p3.`SSN_ID`
group by p1.`SSN_ID`,
p1.Citizen_name,
p1.Company;
Basically you create a new column in a max(case... statement and it will display the value. As mentioned, this gets a bit more complicated if you have unknown values you want as columns. In MySQL you need to use a Prepared Statement so you can use dynamic SQL. Your code would looks sort of like this:
SET #sql = NULL;
SET #sql1 = NULL;
SET #sql2 = NULL;
SET #sql3 = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
' max(case when p2.Family_details = ''',
Family_details,
''' then Family_members_name end) AS `',
Family_details, '`'
)
) INTO #sql1
FROM Table_pivot_02;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
' max(case when p3.Address_type = ''',
Address_type,
''' then Address end) AS `',
Address_type, '`'
)
) INTO #sql2
FROM Table_pivot_03;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
' max(case when p3.PhoneNumber_type = ''',
PhoneNumber_type,
''' then PhoneNumber end) AS `',
PhoneNumber_type, '`'
)
) INTO #sql3
FROM Table_pivot_03
where PhoneNumber_type <> '';
SET #sql = CONCAT('SELECT p1.`SSN_ID`,
p1.Citizen_name,
p1.Company, ', #sql1, ',', #sql2, ',', #sql3, '
from Table_pivot_01 p1
left join Table_pivot_02 p2
on p1.`SSN_ID` = p2.`SSN_ID`
left join Table_pivot_03 p3
on p1.`SSN_ID` = p3.`SSN_ID`
group by p1.`SSN_ID`,
p1.Citizen_name,
p1.Company');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
In this you are creating a long string of the max(case... statements that get concatenated together to then be executed by the database engine. There may be easier ways to get the result you want, but this does work. I've created a demo on rextester to show the code. Both of these produce a result:
+-------+--------+--------------+---------+--------+------------+------------+------------+----------------------+----------------------+------------------------+------------------+--------------------+----------------+
| Row | SSN_ID | Citizen_name | Company | Spouse | Child - 1 | Child - 2 | Child - 3 | Present | Office | Perement | Home | Office | Fax |
+-------+--------+--------------+---------+--------+------------+------------+------------+----------------------+----------------------+------------------------+------------------+--------------------+----------------+
| 1 | 12345 | John | XYZ | Mari | John Jr. 1 | John Jr. 2 | NULL | Address_John_Present | Address_John_Office | Address_John_Perement | John_Home_phone | John_Office_phone | John_FAX_phone |
| 2 | 12346 | Tom | ABC | Ken | NULL | NULL | NULL | Address_Tom_Present | Address_Tom_Office | NULL | Tom_Home_phone | Tom_Office_phone | NULL |
| 3 | 12347 | Jerry | QWER | Suzen | Jerry Jr.1 | Jerry Jr.2 | Jerry Jr.3 | NULL | Address_Jerry_Office | Address_Jerry_Perement | Jerry_Home_phone | Jerry_Office_phone | NULL |
| 4 | 12348 | Joe | PQR | NULL | Joe Jr.1 | Joe Jr.2 | NULL | Address_Joe_Present | Address_Joe_Office | Address_Josh_Perement | Joe_Home_phone | Joe_Office_phone | NULL |
| 5 | 12349 | Josh | NULL | Zoe | Josh Jr.1 | Josh Jr.2 | NULL | Address_Josh_Present | NULL | Address_Josh_Perement | Josh_Home_phone | NULL | Josh_FAX_phone |
+-------+--------+--------------+---------+--------+------------+------------+------------+----------------------+----------------------+------------------------+------------------+--------------------+----------------+
Based on your comment that you might have more than one phone number type per person, you'll need to create a row number for each group of phone types. Unfortunately, again MySQL doesn't have windowing function so you'll need to use user defined variables to get the final result. When you query for PhoneNumber_type you'll need to use something like:
select *
from
(
select SSN_ID, PhoneNumber_type, PhoneNumber,
#num:= case when #group = SSN_ID and #type = PhoneNumber_type then #num +1 else if(#group := SSN_ID, 1, 1) end rn,
#group:= SSN_ID,
#type:=PhoneNumber_type
from Table_pivot_03 t
CROSS JOIN (select #num:=0, #group:=null, #type:=null) c
where t.PhoneNumber_type <> ''
order by SSN_ID, PhoneNumber_type
) as x;
This creates a row number value for each user and phone type. You'd then integrate this into the dynamic SQL code:
SET #sql = NULL;
SET #sql1 = NULL;
SET #sql2 = NULL;
SET #sql3 = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
' max(case when p2.Family_details = ''',
Family_details,
''' then Family_members_name end) AS `',
Family_details, '`'
)
) INTO #sql1
FROM Table_pivot_02;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
' max(case when p3.Address_type = ''',
Address_type,
''' then Address end) AS `',
Address_type, '`'
)
) INTO #sql2
FROM Table_pivot_03;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
' max(case when p.PhoneNumber_type = ''',
PhoneNumber_type,
''' and rn = ', rn, ' then p.PhoneNumber end) AS `',
PhoneNumber_type, rn, '`'
)
) INTO #sql3
FROM
(
select SSN_ID, PhoneNumber_type, PhoneNumber,
#num:= case when #group = SSN_ID and #type = PhoneNumber_type then #num +1 else if(#group := SSN_ID, 1, 1) end rn,
#group:= SSN_ID,
#type:=PhoneNumber_type
from Table_pivot_03 t
CROSS JOIN (select #num:=0, #group:=null, #type:=null) c
where t.PhoneNumber_type <> ''
order by SSN_ID, PhoneNumber_type
) as x;
SET #sql = CONCAT('SELECT p1.`SSN_ID`,
p1.Citizen_name,
p1.Company, ', #sql1, ',', #sql2, ',', #sql3, '
from Table_pivot_01 p1
left join Table_pivot_02 p2
on p1.`SSN_ID` = p2.`SSN_ID`
left join Table_pivot_03 p3
on p1.SSN_ID = p3.SSN_Id
left join
(
select SSN_ID, PhoneNumber_type, PhoneNumber,
#num:= case when #group = SSN_ID and #type = PhoneNumber_type then #num +1 else if(#group := SSN_ID, 1, 1) end rn,
#group:= SSN_ID,
#type:=PhoneNumber_type
from Table_pivot_03 t
CROSS JOIN (select #num:=0, #group:=null, #type:=null) c
where t.PhoneNumber_type <> ''''
order by SSN_ID, PhoneNumber_type
) as p
on p1.SSN_ID = p.SSN_Id
group by p1.`SSN_ID`,
p1.Citizen_name,
p1.Company');
#select #sql;
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
See another demo.
SQL Server Version
Since you've now said that you need a SQL Server version here is that version. SQL Server has a few features that make doing this significantly easier including a PIVOT function, UNPIVOT function, and windowing functions like row_number. Here's a static version of the query with just a few columns pivoted:
select SSN_ID,
Citizen_name,
Company,
Spouse, [Child - 1], [Child - 2], [Child - 3], [Child - 4]
from
(
select SSN_ID,
Citizen_name,
Company,
col,
value
from
(
select
p1.SSN_ID,
p1.Citizen_name,
p1.Company,
p2.Family_details,
p2.Family_members_name,
p3.Address_type,
p3.Address,
PhoneNumber_type = p.PhoneNumber_type + cast(p.rn as varchar(10)),
p.PhoneNumber
from Table_pivot_01 p1
left join Table_pivot_02 p2
on p1.SSN_ID = p2.SSN_ID
left join Table_pivot_03 p3
on p1.SSN_ID = p3.SSN_ID
left join
(
select SSN_ID, PhoneNumber_type, PhoneNumber,
rn = row_number() over(partition by SSN_ID, PhoneNumber_type order by SSN_ID, PhoneNumber_type)
from Table_pivot_03
where PhoneNumber_type <> ''
) p
on p1.SSN_ID = p.SSN_ID
) d
cross apply
(
select 'Family_details', Family_details, Family_members_name union all
select 'Address_type', Address_type, Address union all
select 'PhoneNumber_type', PhoneNumber_type, PhoneNumber
) c(orig, col, value)
) src
pivot
(
max(value)
for col in (Spouse, [Child - 1], [Child - 2], [Child - 3], [Child - 4])
) piv
Then if you need a dynamic sql version the code would be like:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(Col)
from
(
select col, ord
from
(
select
p1.SSN_ID,
p1.Citizen_name,
p1.Company,
p2.Family_details,
p2.Family_members_name,
p3.Address_type,
p3.Address,
PhoneNumber_type = p.PhoneNumber_type + cast(p.rn as varchar(10)),
p.PhoneNumber
from Table_pivot_01 p1
left join Table_pivot_02 p2
on p1.SSN_ID = p2.SSN_ID
left join Table_pivot_03 p3
on p1.SSN_ID = p3.SSN_ID
left join
(
select SSN_ID, PhoneNumber_type, PhoneNumber,
rn = row_number() over(partition by SSN_ID, PhoneNumber_type order by SSN_ID, PhoneNumber_type)
from Table_pivot_03
where PhoneNumber_type <> ''
) p
on p1.SSN_ID = p.SSN_ID
) d
cross apply
(
select 'Family_details', Family_details, Family_members_name, 1 union all
select 'Address_type', Address_type, Address, 2 union all
select 'PhoneNumber_type', PhoneNumber_type, PhoneNumber, 3
) c(orig, col, value, ord)
) d
group by col, ord
order by ord, col
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)') ,1,1,'');
set #query = N'SELECT ' + #cols + N' from
(
select SSN_ID,
Citizen_name,
Company,
col,
value
from
(
select
p1.SSN_ID,
p1.Citizen_name,
p1.Company,
p2.Family_details,
p2.Family_members_name,
p3.Address_type,
p3.Address,
PhoneNumber_type = p.PhoneNumber_type + cast(p.rn as varchar(10)),
p.PhoneNumber
from Table_pivot_01 p1
left join Table_pivot_02 p2
on p1.SSN_ID = p2.SSN_ID
left join Table_pivot_03 p3
on p1.SSN_ID = p3.SSN_ID
left join
(
select SSN_ID, PhoneNumber_type, PhoneNumber,
rn = row_number() over(partition by SSN_ID, PhoneNumber_type order by SSN_ID, PhoneNumber_type)
from Table_pivot_03
where PhoneNumber_type <> ''''
) p
on p1.SSN_ID = p.SSN_ID
) d
cross apply
(
select ''Family_details'', Family_details, Family_members_name union all
select ''Address_type'', Address_type, Address union all
select ''PhoneNumber_type'', PhoneNumber_type, PhoneNumber
) c(orig, col, value)
) src
pivot
(
max(value)
for col in (' + #cols + N')
) p '
exec sp_executesql #query;
Here is another demo.

Related

SQL group by school name

school_name
class
medium
total
srk
1
english
13
srk
2
english
14
srk
3
english
15
srk
1
french
16
srk
2
french
16
srk
3
french
18
vrk
1
english
17
vrk
1
french
18
I want that output by
school_name
class1eng
class1french
class2eng
class2french
class3english
class3french
[output needed][ otput required
output
You’re looking for multiple select statements along with appropriate cases to satisfy.
This should work for you
Select
school_name,
Sum(Case when (class=1 and medium=‘English’) then total else 0 end) as class1english,
Sum(Case when (class=1 and medium=‘French’) then total else 0 end) as class1french,
Sum(Case when (class=2 and medium=‘English’) then total else 0 end) as class2english,
Sum(Case when (class=2 and medium=‘French’) then total else 0 end) as class2french,
Sum(Case when (class=3 and medium=‘English’) then total else 0 end) as class3english,
Sum(Case when (class=3 and medium=‘French’) then total else 0 end) as class3french
From
table_name
Group by
school_name
Seems to be a simple ask, assumed you also want to order your results. Please check below query if that helps
SELECT school_name, class, medium, SUM(total) AS Total
FROM <Table Name>
GROUP BY school_name, class, medium
This solution is for general purpose, complex, but functional.
I've made it for myself as exercise and challenge.
/* --------------- TABLE --------------- */
CREATE TABLE schools_tab
(school VARCHAR(9), class INT, subj VARCHAR(9), total INT);
INSERT INTO schools_tab VALUES
('srk', 1, 'english', 13),
('srk', 2, 'english', 14),
('srk', 3, 'english', 15),
('srk', 1, 'french', 16),
('srk', 2, 'french', 16),
('srk', 3, 'french', 18),
('vrk', 1, 'english', 17),
('vrk', 1, 'french', 18);
/* -------------- DYNAMIC QUERY --------------- */
SET #sql=NULL;
WITH cte AS (
SELECT school, class, subj, ROW_NUMBER() OVER (PARTITION BY school) AS idx, DENSE_RANK() OVER (ORDER BY school) AS ids
FROM (SELECT DISTINCT school FROM schools_tab) A LEFT JOIN (SELECT DISTINCT class, subj FROM schools_tab) B ON (1=1)
), cte2 AS (
SELECT A.ids, A.idx, A.school, A.class, A.subj, COALESCE(B.total, 0) AS total
FROM cte A LEFT JOIN schools_tab B ON (A.school=B.school AND A.class=B.class AND A.subj=B.subj)
), cte3 AS (
SELECT DISTINCT class, subj
FROM schools_tab
ORDER BY class, subject
)
SELECT CONCAT('WITH RECURSIVE cte AS (
SELECT school, class, subj, ROW_NUMBER() OVER (PARTITION BY school) AS idx, DENSE_RANK() OVER (ORDER BY school) AS ids
FROM (SELECT DISTINCT school FROM schools_tab) A LEFT JOIN (SELECT DISTINCT class, subj FROM schools_tab) B ON (1=1)
), cte2 AS (
SELECT A.ids, A.idx, A.school, A.class, A.subj, COALESCE(B.total, 0) AS total
FROM cte A LEFT JOIN schools_tab B ON (A.school=B.school AND A.class=B.class AND A.subj=B.subj)
), ctx AS ('
'SELECT (SELECT MAX(ids) FROM cte2) AS n,',
GROUP_CONCAT(DISTINCT CONCAT( '(SELECT total FROM cte2 WHERE idx=',idx,' AND ids=n) AS class',class,subj ) ORDER BY class, subj),
' UNION ALL SELECT n-1 AS n,',
GROUP_CONCAT(DISTINCT CONCAT( '(SELECT total FROM cte2 WHERE idx=',idx,' AND ids=n) AS class',class,subj ) ORDER BY class, subj),
' FROM ctx WHERE n>0',
') SELECT DISTINCT SUBSTRING_INDEX(SUBSTRING_INDEX(''srk,vrk'', '','', n+1), '','', -1) AS school,',
GROUP_CONCAT(DISTINCT CONCAT('class',class,subj)),
' FROM ctx ORDER BY school'
) INTO #sql
FROM cte2;
PREPARE stmt1 FROM #sql;
EXECUTE stmt1;

How can I get this pivot kind of output in sql

Consider my source table as given below i.e customer.
How can i get the required output as shown using sql (oracle or mysql)
customer :
customer id Purchase_id cashback
123 abc111 5
123 abc112 5
123 abc113 2
345 abc311 0
345 abc312 2
678 abc611 4
678 abc612 3
678 abc613 5
Output Needed:
ID purchare_id_1 purchare_id_2 purchare_id_3 cashback_1 cashback_2 cashback_3
123 abc111 abc112 abc113 5 5 2
345 abc311 abc312 0 2
678 abc611 abc612 abc613 4 3 5
DML and DDL:
create table cust_table (
customer_id int, Purchase_id varchar(100), cashback int
);
insert into cust_table values
(123 , 'abc111' , 5),
(123 , 'abc112' , 5),
(123 , 'abc113' , 2),
( 345 , 'abc311' , 0),
(345 , 'abc312' , 2),
(678 , 'abc611' , 4),
(678 , 'abc612' , 3),
(678 , 'abc613' , 5);
commit;
PS:
Data might be not static, it can change.
WITH
cte AS ( SELECT *, ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY Purchase_id) rn
FROM cust_table )
SELECT customer_id,
MAX(CASE WHEN rn=1 THEN Purchase_id END) purchase_1,
MAX(CASE WHEN rn=2 THEN Purchase_id END) purchase_2,
MAX(CASE WHEN rn=3 THEN Purchase_id END) purchase_3,
MAX(CASE WHEN rn=1 THEN cashback END) cashback_1,
MAX(CASE WHEN rn=2 THEN cashback END) cashback_2,
MAX(CASE WHEN rn=3 THEN cashback END) cashback_3
FROM cte
GROUP BY customer_id
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=ec2de721d7089a82a5f7ae669ce2d19e
In MySQL: You can use concat along with group by to see partial result like as below
select customer_id, group_concat(`Purchase_id` separator ',') as `Purchase_idX`,
group_concat(`cashback` separator ',') as `cashbackX` from cust_table
group by customer_id;
If you want the exact result run the below query:
select
SUBSTRING_INDEX(AA, ',', 1) as purchare_id_1,
CASE
WHEN LOCATE(',', AA, 2) = 0 THEN NULL
ELSE SUBSTRING_INDEX(SUBSTRING_INDEX(AA, ',', 2), ',', -1)
END AS purchare_id_2,
CASE
WHEN LOCATE(',', AA, LOCATE(',', AA, 1)+1) = 0 THEN NULL
ELSE SUBSTRING_INDEX(SUBSTRING_INDEX(AA, ',', 3), ',', -1)
END AS cashback_1,
SUBSTRING_INDEX(BB, ',', 1) as purchare_id_1,
CASE
WHEN LOCATE(',', BB, 2) = 0 THEN NULL
ELSE SUBSTRING_INDEX(SUBSTRING_INDEX(BB, ',', 2), ',', -1)
END AS cashback_2,
CASE
WHEN LOCATE(',', BB, LOCATE(',', BB, 1)+1) = 0 THEN NULL
ELSE SUBSTRING_INDEX(SUBSTRING_INDEX(BB, ',', 3), ',', -1)
END AS cashback_3
from
( select customer_id, group_concat(`Purchase_id` separator ',') as AA, group_concat(`cashback` separator ',') as BB,
group_concat(`cashback` separator ',') as `cashbackX` from cust_table
group by customer_id) as TB

How to make this sql query compatible for older verisons of mysql such v.5.5 and above?

I have this query it works on MySQL 8.0 but not on the below versions like MySQL 5.5. How to make this compatible as I am getting this error on web server: #1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(partition by pid order by age' at line 11
SELECT p.id, p.pid, p.name,
MAX(CASE WHEN t.dr = 1 THEN t.name END) as name1,
MAX(CASE WHEN t.dr = 1 THEN age END) as age1,
MAX(CASE WHEN t.dr = 2 THEN t.name END) as name2,
MAX(CASE WHEN t.dr = 2 THEN t.age END) as age2,
MAX(CASE WHEN t.dr = 3 THEN t.name END) as name3,
MAX(CASE WHEN t.dr = 3 THEN t.age END) as age3,
MAX(CASE WHEN t.dr = 4 THEN t.name END) as name4,
MAX(CASE WHEN t.dr = 4 THEN t.age END) as age4
FROM Table1 p
join (select id , pid, name, age, DENSE_RANK() OVER (partition by pid order by age) as dr
from Table2) t on p.pid= t.pid
group by p.id, p.pid, p.name
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=d324e7654218dae3d1168df2bf529099
select version();
version()
5.5.62
Schema:
CREATE TABLE Table1
(id int , name varchar(15) , pid int )
INSERT INTO Table1
values (1, 'Jack', 1521),
(2, 'Steve',1522)
CREATE TABLE Table2
(id int, pid int, name varchar(15), age int);
INSERT INTO Table2
VALUES
(1, 1521, 'John', 12),
(2, 1521, 'Maria', 7),
(3, 1521, 'Larry', 3),
(4, 1522, 'Harry', 5)
Query:
SELECT p.id, p.pid, p.name,
MAX(CASE WHEN t.dr = 1 THEN t.name END) as name1,
MAX(CASE WHEN t.dr = 1 THEN age END) as age1,
MAX(CASE WHEN t.dr = 2 THEN t.name END) as name2,
MAX(CASE WHEN t.dr = 2 THEN t.age END) as age2,
MAX(CASE WHEN t.dr = 3 THEN t.name END) as name3,
MAX(CASE WHEN t.dr = 3 THEN t.age END) as age3,
MAX(CASE WHEN t.dr = 4 THEN t.name END) as name4,
MAX(CASE WHEN t.dr = 4 THEN t.age END) as age4
FROM Table1 p
join (select id , pid, name, age, (select count(*) from Table2 t2
where t.pid=t2.pid and t2.age<=t.age) as dr
from Table2 t) t on p.pid= t.pid
group by p.id, p.pid, p.name
Output:
id
pid
name
name1
age1
name2
age2
name3
age3
name4
age4
1
1521
Jack
Larry
3
Maria
7
John
12
null
null
2
1522
Steve
Harry
5
null
null
null
null
null
null
db<>fiddle here
One method is a correlated subquery to replace DENSE_RANK():
FROM Table1 p JOIN
(SELECT t2.*,
(SELECT COUNT(DISTINCT tt2.age)
FROM table2 tt2
WHERE tt2.pid = t2.pid AND
tt2.age <= t2.age
) as dr
FROM Table2 t2
) t
ON p.pid = t.pid
Here is a db<>fiddle.

Mysql left join table2 where field from table3

table media
id, options
1 a
2 b
3 c
table maps
id, title, type
1 f x
2 g x
3 h y
4 z x
4 w y
table media maps
maps_id media_id
1 2
2 3
I am trying to select all data from table media and join table maps. Each media can contain multiple maps.
SELECT media_t.id, media_t.options,
GROUP_CONCAT(CASE WHEN maps_t.type = 'x' THEN maps_t.title END ORDER BY maps_t.title SEPARATOR ', ') as x,
GROUP_CONCAT(CASE WHEN maps_t.type = 'y' THEN maps_t.title END ORDER BY maps_t.title SEPARATOR ', ') as y
FROM media_table as media_t
LEFT JOIN maps_table as maps_t
ON media_t.id = (
SELECT maps_id FROM {table_media_maps}
WHERE media_id = maps_t.id
)
GROUP BY media_t.id
If you need a 3 tbals join you could try
SELECT me.id, me.options,
GROUP_CONCAT(CASE WHEN ma.type = 'x' THEN ma.title END ORDER BY ma.title SEPARATOR ', ') as x,
GROUP_CONCAT(CASE WHEN ma.type = 'y' THEN ma.title END ORDER BY ma.title SEPARATOR ', ') as y
FROM media as me
LEFT JOIN media_maps mm on me-id = mm.media_id
LEFT JOIN maps ma ON mm.maps_id = ma.id
GROUP BY me.id
your data is not coplete, for all case.
I put a right join for the maps table, so that you cansee that it works, problably you want there also a left join, but you still need to join all three tables
CREATE TABLE media_table (
`id` INTEGER,
`options` VARCHAR(1)
);
INSERT INTO media_table
(`id`, `options`)
VALUES
('1', 'a'),
('2', 'b'),
('3', 'c');
CREATE TABLE table_media_maps (
`maps_id` INTEGER,
`media_id` INTEGER
);
INSERT INTO table_media_maps
(`maps_id`, `media_id`)
VALUES
('1', '2'),
('2', '3');
CREATE TABLE maps_table (
`id` INTEGER,
`title` VARCHAR(1),
`type` VARCHAR(1)
);
INSERT INTO maps_table
(`id`, `title`, `type`)
VALUES
('1', 'f', 'x'),
('2', 'g', 'x'),
('3', 'h', 'y'),
('4', 'z', 'x'),
('4', 'w', 'y');
SELECT media_t.id, media_t.options,
GROUP_CONCAT(
CASE WHEN maps_t.type = 'x' THEN maps_t.title END
ORDER BY maps_t.title SEPARATOR ', ')
as x,
GROUP_CONCAT(
CASE WHEN maps_t.type = 'y' THEN maps_t.title END
ORDER BY maps_t.title SEPARATOR ', ')
as y
FROM media_table as media_t
LEFT JOIN table_media_maps m_m_t ON media_t.id = m_m_t.media_id
right JOIN maps_table as maps_t
ON maps_t.id = m_m_t.maps_id
GROUP BY media_t.id, media_t.options
id | options | x | y
---: | :------ | :- | :---
null | null | z | h, w
2 | b | f | null
3 | c | g | null
db<>fiddle here

how to make a apriori table with dynamicaly mysql

i have 3 tables like this
create table order_match
(
id int(10) PRIMARY KEY not null,
order_status_id int(10) not null
);
create table order_match_detail
(
id int(10) PRIMARY KEY not null,
order_match_id int(10) not null,
product_id int(10) NOT NULL
);
create table product
(
id int(10) PRIMARY KEY not null,
name varchar(255) not null
);
Insert into order_match (id, order_status_id)
select 1, 6 union all
select 2, 7 union all
select 3, 6 union all
select 4, 6;
Insert into order_match_detail (id, order_match_id, product_id)
select 1, 1, 147 union all
select 2, 2, 148 union all
select 3, 3, 147 union all
select 4, 4, 149 union all
select 5, 4, 147;
Insert into product (id, name)
select 147, 'orange' union all
select 148, 'carrot' union all
select 149, 'Apple';
with order_match.id = order_match_detail.order_match_id
and order_match_detail.product_id = product.id
i want to make the data where order_status_id not in 7 then it's success transaction and from that success transaction, if the transaction buy apple, then the column of apple contain 1 else if not buying, then 0 and this is my expected results, i want to make this data to analyze in
id (in order_match) | Orange | Carrot | Apple
1 1 0 0
3 1 0 0
4 1 0 1
with that problem i can solve it with this query
select om.id,
count(DISTINCT case when omd.product_id = 147 THEN 1 END) Orange,
count(DISTINCT case when omd.product_id = 148 THEN 1 END) Carrot,
count(DISTINCT case when omd.product_id = 149 THEN 1 END) Apple
from order_match om
left join order_match_detail omd
on om.id = omd.order_match_id
where om.order_status_id in (4, 5, 6, 8)
group by om.id
the real problem is, in my real database, it's contain 1550 product_id, how to make it automatically so no need to input manual the product_id untill 1550 product_id
this is the fiddle https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=c0eb7fe1b012ab1c909d37e325a8d434
i've tried the new queries like this and it still wrong
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'count(case when product.name = ''',
product.name,
''' then 1 end) AS ',
replace(product.name, ' ', '')
)
) INTO #sql
from product;
SET #sql = CONCAT('SELECT omd.order_match_id, ', #sql, ' from order_match_detail omd
left join order_match om
on omd.order_match_id = om.id
left join product p
on omd.product_id = p.id
where om.order_status_id in (4, 5, 6, 8)
group by omd.order_match_id');
PREPARE stmt FROM #sql;
EXECUTE stmt;
your query is almost correct you were missing on alias instead of p you should use 'product' in second query, it would work
SET group_concat_max_len = 1000000;
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'count(case when product.name = ''',
product.name,
''' then 1 end) AS ',
'"',replace(product.name, ' ', ''),'"'
)
) INTO #sql
from product;
SET #sql = CONCAT('SELECT omd.order_match_id as id, ', #sql, ' from order_match_detail omd
left join order_match om
on omd.order_match_id = om.id
left join product product
on omd.product_id = product.id
where om.order_status_id in (4, 5, 6, 8)
group by omd.order_match_id');
PREPARE stmt FROM #sql;
EXECUTE stmt;
You can remove DISTINCT from GROUP_CONCAT(DISTINCT if you are sure that product id's is having unique names for each id's
Then i would get the exact result as you mentioned in question else just you will see, Apple column first and Orange column last, overall result is as expected.