Home > Back-end >  Mysql Pivot Query / Suggestion
Mysql Pivot Query / Suggestion

Time:10-07

There is 3 tables

Table User

user_id created_at
1001 2022-10-01
1002 2022-10-02
1003 2022-10-03
1004 2022-10-04
1005 2022-10-05

Table Default_Properties

def_id type value
10 type_a val_a
11 type_b val_b
12 type_c val_c
13 type_d val_d
14 type_e val_e

Table Custom_Properties

pro_id fk_user_id type value
20 1002 type_b banana
21 1005 type_d durian

By default, every user will have default properties, unless overwritten with custom one. Thus, expected result as listed below:

Expected Result

user_id type_a type_b type_c type_d type_e
1001 val_a val_b val_c val_d val_e
1002 val_a banana val_c val_d val_e
1003 val_a val_b val_c val_d val_e
1004 val_a val_b val_c val_d val_e
1005 val_a val_b val_c durian val_e

I tried to pivot it by using "case when" but have no luck to get the expected result. Highly appreciate for any query help/suggestion provided. Thank you!

CodePudding user response:

SELECT u.user_id,
  MAX(CASE d.type WHEN 'type_a' THEN COALESCE(c.value, d.value) END) AS type_a,
  MAX(CASE d.type WHEN 'type_b' THEN COALESCE(c.value, d.value) END) AS type_b,
  MAX(CASE d.type WHEN 'type_c' THEN COALESCE(c.value, d.value) END) AS type_c,
  MAX(CASE d.type WHEN 'type_d' THEN COALESCE(c.value, d.value) END) AS type_d,
  MAX(CASE d.type WHEN 'type_e' THEN COALESCE(c.value, d.value) END) AS type_e
FROM user AS u
CROSS JOIN Default_Properties AS d 
LEFT OUTER JOIN Custom_Properties AS c ON u.user_id=c.fk_user_id AND c.type=d.type
GROUP BY u.user_id
ORDER BY u.user_id;

Output, tested on MySQL 8.0.29:

 --------- -------- -------- -------- -------- -------- 
| user_id | type_a | type_b | type_c | type_d | type_e |
 --------- -------- -------- -------- -------- -------- 
|    1001 | val_a  | val_b  | val_c  | val_d  | val_e  |
|    1002 | val_a  | banana | val_c  | val_d  | val_e  |
|    1003 | val_a  | val_b  | val_c  | val_d  | val_e  |
|    1004 | val_a  | val_b  | val_c  | val_d  | val_e  |
|    1005 | val_a  | val_b  | val_c  | durian | val_e  |
 --------- -------- -------- -------- -------- -------- 

It's not possible in SQL to do "dynamic columns."

Columns must be fixed at the time the query is parsed, which is before it has read any of the data in the table. So there's no way a query can expand the columns as it reads data, beyond those you name explicitly in the select-list when you write the query.

By analogy, this would be like calling a Java function whose name is the return value of the function.

So to do an effective pivot table, if the properties you want to make columns for may change, then you must do the query as two steps: first know the set of properties you want to make columns for. Something like the following would give you the list of properties:

SELECT DISTINCT type FROM Default_Properties
UNION
SELECT DISTINCT type FROM Custom_Properties;

Then use the result of that query to build your pivot table query. (I.e. a loop of code, appending expressions to the select-list of a query as strings.)

  • Related