I'm creating an employee tracking app.
I have a MySQL table which is as follows:
ID | PersonID | TypeID | DateTime |
---|---|---|---|
1 | 001 | IN | 2022-09-01T13:21:12 |
2 | 001 | OUT | 2022-09-01T13:25:12 |
3 | 001 | IN | 2022-09-01T14:21:12 |
4 | 001 | OUT | 2022-09-01T14:25:12 |
5 | 002 | IN | 2022-09-03T13:21:12 |
6 | 002 | OUT | 2022-09-03T13:25:12 |
7 | 002 | IN | 2022-09-03T14:21:12 |
8 | 002 | IN | 2022-09-03T14:25:12 |
9 | 002 | OUT | 2022-09-03T14:25:12 |
10 | 002 | OUT | 2022-09-03T16:25:12 |
11 | 002 | OUT | 2022-09-03T17:25:12 |
12 | 002 | IN | 2022-09-04T16:25:12 |
13 | 002 | IN | 2022-09-05T17:25:12 |
I would like to create a view that returns records first sorted by PersonID and then by the ID but transforms the rows into columns.
Something like this:
PersonID | InID | In_DateTime | OutID | Out_DateTime |
---|---|---|---|---|
001 | 1 | 2022-09-01T13:21:12 | 2 | 2022-09-01T13:25:12 |
001 | 3 | 2022-09-01T14:21:12 | 4 | 2022-09-01T14:25:12 |
002 | 5 | 2022-09-03T13:21:12 | 6 | 2022-09-03T13:25:12 |
002 | 7 | 2022-09-03T14:21:12 | null | null |
002 | 8 | 2022-09-03T14:25:12 | 9 | 2022-09-03T14:25:12 |
002 | null | null | 10 | 2022-09-03T16:25:12 |
002 | null | null | 11 | 2022-09-03T17:25:12 |
002 | 12 | 2022-09-04T16:25:12 | null | null |
002 | 13 | 2022-09-05T17:25:12 | null | null |
Does anyone have an idea how to do this in MySQL?
Thanks for any suggestions.
CodePudding user response:
Use window functions LEAD()
or LAG()
to get for each row its pair row, depending on its TypeID
and do a left join of the results to the table:
WITH cte AS (
SELECT *,
CASE
WHEN TypeID = 'IN' AND LEAD(TypeID) OVER w = 'OUT' THEN LEAD(ID) OVER w
WHEN TypeID = 'OUT' AND LAG(TypeID) OVER w = 'IN' THEN LAG(ID) OVER w
END other_ID
FROM tablename
WINDOW w AS (PARTITION BY PersonID ORDER BY DateTime)
)
SELECT DISTINCT c.PersonID,
CASE WHEN c.TypeID = 'IN' THEN c.ID ELSE t.ID END InID,
CASE WHEN c.TypeID = 'IN' THEN c.DateTime ELSE t.DateTime END In_DateTime,
CASE WHEN c.TypeID = 'IN' THEN t.ID ELSE c.ID END OutID,
CASE WHEN c.TypeID = 'IN' THEN t.DateTime ELSE c.DateTime END Out_DateTime
FROM cte c LEFT JOIN tablename t
ON t.ID = c.other_ID
ORDER BY c.PersonID, COALESCE(In_DateTime, Out_DateTime);
See the demo.