patternsqlMinor
group_concat and group by together
Viewed 0 times
andtogethergroupgroup_concat
Problem
I am trying to write a query using
Here's how my data is...
expected query result
Any help is greatly appreciated.
group_concat, concat and other functions, but I am getting stuck not able to join and group the data to represent them in 1 cell. Here's how my data is...
table1
+-----+---------+
| id | ... |
+-----+---------+
| 1 | |
| 2 | |
| 3 | |
+-----+---------+
table2
+-----+-----+-------+
| id | env | infid |
+-----+-----+-------+
| 1 | p | 10 |
| 1 | p | 11 |
| 1 | p | 20 |
| 1 | p | 12 |
| 1 | D | 21 |
| 1 | D | 22 |
+-----+-----+-------+
table3
+-------+---------+---------+
| infid | inftype | infname |
+-------+---------+---------+
| 10 | Srv | abc |
| 20 | Srv | xyz |
| 11 | Db | hgj |
| 12 | Db | kjk |
| 21 | Srv | pop |
| 22 | Db | kli |
+-------+---------+---------+expected query result
+-----+------------------------------+---------------------+
| id | P | D |
+------------------------------------+---------------------+
| 1 |Srv: [abc, xyz] Db: [hgj, kjk]|Srv: [pop] Db: [Kli] |
+-----+------------------------------+---------------------+Any help is greatly appreciated.
Solution
It is possible to get to the desired result in a simpler way.
First, you could start with this simple query:
This is what you would get as the result for your data samples:
Next, you could use the above result as a derived table and group it by
The result would be very close to what you want:
In order to split the
However, there is no need to resort to duplicating subqueries like that, because you can pivot the results using conditional aggregation. Instead of grouping by
You can verify for yourself that the result of the last query would match your requirements:
First, you could start with this simple query:
SELECT
t1.id,
t2.env,
CONCAT(t3.inftype,
': [',
GROUP_CONCAT(t3.infname ORDER BY t3.infname SEPARATOR ', '),
']'
) AS inftypeandnames
FROM
table1 AS t1
INNER JOIN table2 AS t2 ON t1.id = t2.id
INNER JOIN table3 AS t3 ON t2.infid = t3.infid
GROUP BY
t1.id,
t2.env,
t3.inftypeThis is what you would get as the result for your data samples:
id env inftypeandnames
-- --- ---------------
1 D Db: [kli]
1 D Srv: [pop]
1 P Db: [hgj, kjk]
1 P Srv: [abc, xyz]Next, you could use the above result as a derived table and group it by
id, env, concatenating the inftypeandnames values, like this:SELECT
id,
env,
GROUP_CONCAT(inftypeandnames ORDER BY inftypeandnames DESC SEPARATOR ' ') AS inftypesandnames
FROM
(
SELECT
t1.id,
t2.env,
CONCAT(t3.inftype,
': [',
GROUP_CONCAT(t3.infname ORDER BY t3.infname SEPARATOR ', '),
']'
) AS inftypeandnames
FROM
table1 AS t1
INNER JOIN table2 AS t2 ON t1.id = t2.id
INNER JOIN table3 AS t3 ON t2.infid = t3.infid
GROUP BY
t1.id,
t2.env,
t3.inftype
) AS s
GROUP BY
id,
envThe result would be very close to what you want:
id env inftypesandnames
-- --- ------------------------------
1 D Srv: [pop] Db: [kli]
1 P Srv: [abc, xyz] Db: [hgj, kjk]In order to split the
inftypesandnames values into separate columns based on the values of env, you could duplicate the above query, apply a filter on env to each copy (env = 'D', env = 'P' and so on if there can be others), join the results and return each subset's inftypesandnames value in its own column – same as Rolando has suggested, although I would argue that you might need a full outer join rather than an inner join if it is possible for some ids to have only D while for some others only P. Since MySQL does not support the FULL JOIN / FULL OUTER JOIN syntax and the usual workaround to that is a union of a left join and a right join, I suspect the final query in this case would make Rolando's brain hurt even more.However, there is no need to resort to duplicating subqueries like that, because you can pivot the results using conditional aggregation. Instead of grouping by
id, env in the outer query, you would be grouping by id only and conditionally apply GROUP_CONCAT to the inftypeandnames values based on env, like this:SELECT
id,
GROUP_CONCAT(CASE env WHEN 'P' THEN inftypeandnames END ORDER BY inftypeandnames DESC SEPARATOR ' ') AS P,
GROUP_CONCAT(CASE env WHEN 'D' THEN inftypeandnames END ORDER BY inftypeandnames DESC SEPARATOR ' ') AS D
FROM
(
SELECT
t1.id,
t2.env,
CONCAT(t3.inftype,
': [',
GROUP_CONCAT(t3.infname ORDER BY t3.infname SEPARATOR ', '),
']'
) AS inftypeandnames
FROM
table1 AS t1
INNER JOIN table2 AS t2 ON t1.id = t2.id
INNER JOIN table3 AS t3 ON t2.infid = t3.infid
GROUP BY
t1.id,
t2.env,
t3.inftype
) AS s
GROUP BY
id
;You can verify for yourself that the result of the last query would match your requirements:
id P D
-- ------------------------------ --------------------
1 Srv: [abc, xyz] Db: [hgj, kjk] Srv: [pop] Db: [kli]Code Snippets
SELECT
t1.id,
t2.env,
CONCAT(t3.inftype,
': [',
GROUP_CONCAT(t3.infname ORDER BY t3.infname SEPARATOR ', '),
']'
) AS inftypeandnames
FROM
table1 AS t1
INNER JOIN table2 AS t2 ON t1.id = t2.id
INNER JOIN table3 AS t3 ON t2.infid = t3.infid
GROUP BY
t1.id,
t2.env,
t3.inftypeid env inftypeandnames
-- --- ---------------
1 D Db: [kli]
1 D Srv: [pop]
1 P Db: [hgj, kjk]
1 P Srv: [abc, xyz]SELECT
id,
env,
GROUP_CONCAT(inftypeandnames ORDER BY inftypeandnames DESC SEPARATOR ' ') AS inftypesandnames
FROM
(
SELECT
t1.id,
t2.env,
CONCAT(t3.inftype,
': [',
GROUP_CONCAT(t3.infname ORDER BY t3.infname SEPARATOR ', '),
']'
) AS inftypeandnames
FROM
table1 AS t1
INNER JOIN table2 AS t2 ON t1.id = t2.id
INNER JOIN table3 AS t3 ON t2.infid = t3.infid
GROUP BY
t1.id,
t2.env,
t3.inftype
) AS s
GROUP BY
id,
envid env inftypesandnames
-- --- ------------------------------
1 D Srv: [pop] Db: [kli]
1 P Srv: [abc, xyz] Db: [hgj, kjk]SELECT
id,
GROUP_CONCAT(CASE env WHEN 'P' THEN inftypeandnames END ORDER BY inftypeandnames DESC SEPARATOR ' ') AS P,
GROUP_CONCAT(CASE env WHEN 'D' THEN inftypeandnames END ORDER BY inftypeandnames DESC SEPARATOR ' ') AS D
FROM
(
SELECT
t1.id,
t2.env,
CONCAT(t3.inftype,
': [',
GROUP_CONCAT(t3.infname ORDER BY t3.infname SEPARATOR ', '),
']'
) AS inftypeandnames
FROM
table1 AS t1
INNER JOIN table2 AS t2 ON t1.id = t2.id
INNER JOIN table3 AS t3 ON t2.infid = t3.infid
GROUP BY
t1.id,
t2.env,
t3.inftype
) AS s
GROUP BY
id
;Context
StackExchange Database Administrators Q#110712, answer score: 7
Revisions (0)
No revisions yet.