id | user | manager_id | manager_name | hierarchy | level_1 | level_2 | level_3 | level_4 |
---|---|---|---|---|---|---|---|---|
100 | A | 30 | peter | 1 | brian | null | null | null |
100 | A | null | null | 2 | null | koby | null | null |
100 | A | null | null | 3 | null | null | peter | null |
200 | B | 20 | koby | 1 | null | brian | null | null |
200 | B | null | null | 2 | peter | null | null | null |
200 | B | null | null | 3 | null | null | koby | null |
300 | C | 10 | brian | 1 | peter | null | null | null |
300 | C | null | null | 2 | null | koby | null | null |
300 | C | null | null | 3 | null | null | brian | null |
How to pivot the rows values to existing columns so as to retain one row for one user?
id | user | manager_id | manager_name | hierarchy | level_1 | level_2 | level_3 | level_4 |
---|---|---|---|---|---|---|---|---|
100 | A | 30 | peter | 4 | brian | koby | peter | null |
200 | B | 20 | koby | 4 | peter | brian | koby | null |
300 | C | 10 | brian | 4 | peter | koby | brian | null |
Note: Each level will have only one value for each user.
CodePudding user response:
Given your premise of one single value on aggregated fields for each user, you can just use aggregation with the MAX
funtion for each non-aggregated field:
SELECT id, [user],
MAX(manager_id) AS manager_id,
MAX(manager_name) AS manager_name,
MAX(hierarchy) 1 AS hierarchy,
MAX(level_1) AS level_1,
MAX(level_2) AS level_2,
MAX(level_3) AS level_3,
MAX(level_4) AS level_4
FROM tab
GROUP BY id, [user]
Check the demo here.
CodePudding user response:
I would use STRING_AGG
here because I dislike the risk to lose data if multiple levels per row are NOT NULL
or a user has multiple names per level in different rows.
If this doesn't happen, the result is the same as when using MAX
or MIN
.
If it does happen, we will get every name per level instead of one only.
SELECT id,
MAX(user_id) AS user_id,
MAX(manager_id) AS manager_id,
MAX(manager_name) AS manager_name,
MAX(hierarchy) 1 AS hierarchy,
STRING_AGG(level_1,',') AS level_1,
STRING_AGG(level_2,',') AS level_2,
STRING_AGG(level_3,',') AS level_3,
STRING_AGG(level_4,',') AS level_4
FROM yourtable
GROUP BY id;
Replicate the difference here: db<>fiddle
Even considering your statement there is always one name per level only, I would not risk that. In a week or a month, things might differ.
Sidenote: I renamed "user" to "user_id" in my example because I refuse to use SQL key words as column name or table name. I recommend to avoid that if not urgently necessary.