Hi I want to know how can do a pivot table with crosstable in a table like:
user_id | action | time |
---|---|---|
1 | a | 2022-01-01 12:30 |
1 | b | 2022-01-01 12:40 |
1 | b | 2022-01-01 12:50 |
1 | c | 2022-01-01 13:00 |
1 | c | 2022-01-01 13:10 |
1 | c | 2022-01-01 13:20 |
2 | b | 2022-01-01 13:11 |
2 | c | 2022-01-01 13:21 |
The expected result should look like this:
user_id | a | b | c |
---|---|---|---|
1 | 2022-01-01 12:30 | 2022-01-01 12:40 | 2022-01-01 13:00 |
1 | NULL | 2022-01-01 12:50 | 2022-01-01 13:10 |
1 | NULL | NULL | 2022-01-01 13:20 |
2 | NULL | 2022-01-01 13:11 | 2022-01-01 13:21 |
Following several tutorials, they gave me this result:
user_id | a | b | c |
---|---|---|---|
1 | 2022-01-01 12:30 | 2022-01-01 12:40 | 2022-01-01 13:00 |
2 | NULL | 2022-01-01 13:11 | 2022-01-01 13:21 |
However, as you can note, there is plenty of data loss by the single line result. Does any have an idea, please? Thanks in advance
Here is the SQL:
with action_a
as
(
SELECT user_id,
Row_number()
OVER (
ORDER BY a) id,
a
FROM (SELECT user_id,
CASE
WHEN action = 'a' THEN time
END "a"
FROM tabaction) x
),
action_b
as
(
SELECT user_id,
Row_number()
OVER (
ORDER BY b) id,
b
FROM (SELECT user_id,
CASE
WHEN action = 'b' THEN time
END "b"
FROM tabaction) x
),
action_c
as
(
SELECT user_id,
Row_number()
OVER (
ORDER BY c) id,
c
FROM (SELECT user_id,
CASE
WHEN action = 'c' THEN time
END "c"
FROM tabaction) x
)
SELECT action_a.user_id,
action_a.a,
action_b.b,
action_c.c
FROM action_a
FULL OUTER JOIN action_b
ON action_a.id = action_b.id
AND action_a.user_id = action_b.user_id
FULL OUTER JOIN action_c
ON action_b.id = action_c.id
AND action_b.user_id = action_c.user_id;
Output:
user_id | a | b | c
---------+---------------------+---------------------+---------------------
1 | 2022-01-01 12:30:00 | 2022-01-01 12:30:00 | 2022-01-01 12:00:00
1 | | 2022-01-01 12:50:00 | 2022-01-01 13:10:00
1 | | | 2022-01-01 13:20:00
1 | | |
1 | | |
1 | | |
(6 rows)
Setup:
create table tabaction
( user_id int, action varchar(5) , time timestamp);
insert into tabaction values(1,'a','2022-01-01 12:30'),(1,'b','2022-01-01 12:30'),(1,'b','2022-01-01 12:50'),(1,'c','2022-01-01 12:00'),(1,'c','2022-01-01 13:10'),(1,'c','2022-01-01 13:20');
postgres=# select * from tabaction;
user_id | action | time
---------+--------+---------------------
1 | a | 2022-01-01 12:30:00
1 | b | 2022-01-01 12:50:00
1 | c | 2022-01-01 12:00:00
1 | c | 2022-01-01 13:10:00
1 | c | 2022-01-01 13:20:00
1 | b | 2022-01-01 12:30:00
(6 rows)
Ideal SQL should include user_id for action A, B, C so that those not missed out. Here the situation does not arise because USER_ID is only 1 and all actions are mapped to USER_ID. I believe might get different, in which case you might need this SQL:
with action_a
as
(
SELECT user_id,
Row_number()
OVER (
ORDER BY a) id,
a
FROM (SELECT user_id,
CASE
WHEN action = 'a' THEN time
END "a"
FROM tabaction) x
),
action_b
as
(
SELECT user_id,
Row_number()
OVER (
ORDER BY b) id,
b
FROM (SELECT user_id,
CASE
WHEN action = 'b' THEN time
END "b"
FROM tabaction) x
),
action_c
as
(
SELECT user_id,
Row_number()
OVER (
ORDER BY c) id,
c
FROM (SELECT user_id,
CASE
WHEN action = 'c' THEN time
END "c"
FROM tabaction) x
)
SELECT action_a.user_id a_userid,
action_b.user_id b_userid,
action_c.user_id c_userid,
action_a.a,
action_b.b,
action_c.c
FROM action_a
FULL OUTER JOIN action_b
ON action_a.id = action_b.id
AND action_a.user_id = action_b.user_id
FULL OUTER JOIN action_c
ON action_b.id = action_c.id
AND action_b.user_id = action_c.user_id;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.