Home > Software design >  pivot rows to columns and retain one row for one user
pivot rows to columns and retain one row for one user

Time:12-23

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.

  • Related