I’m trying to write a query in Oracle SQL that aggregates values by some ids, where I have the following table as an input:
ID | SOME_DATE | RANK_POSITION |
---|---|---|
301 | 20211201 | 1 |
301 | 20211202 | 2 |
301 | 20211203 | 3 |
649 | 20211201 | 1 |
649 | 20211202 | 2 |
649 | 20211206 | 3 |
649 | 20211208 | 4 |
649 | 20211211 | 5 |
758 | 20211212 | 1 |
758 | 20211222 | 2 |
And y want to obtain something like this:
ID | FIRST_IN_RANK_DATE | SECOND_IN_RANK_DATE |
---|---|---|
301 | 01/12/2021 | 02/12/2021 |
649 | 01/12/2021 | 02/12/2021 |
758 | 12/12/2021 | 22/12/2021 |
Where FIRST_IN_RANK_DATE
, is the date that is the first in the RANK_POSITION
for the ID
, and SECOND_IN_RANK_DATE
is the date that is second in RANK_POSITION
for the specific ID
.
Advertisement
Answer
You can use conditional aggregation:
x
SELECT id,
MAX(CASE rank_position WHEN 1 THEN some_date END) AS first_in_rank_date,
MAX(CASE rank_position WHEN 2 THEN some_date END) AS second_in_rank_date
FROM table_name
GROUP BY id
Or PIVOT
:
SELECT *
FROM table_name
PIVOT (
MAX(some_date)
FOR rank_position IN (
1 AS first_in_rank_date,
2 AS second_in_rank_date
)
)
Or, from Oracle 12, MATCH_RECOGNIZE
:
SELECT *
FROM table_name
MATCH_RECOGNIZE (
PARTITION BY id
ORDER BY rank_position
MEASURES
rank1.some_date AS first_in_rank_date,
rank2.some_date AS second_in_rank_date
PATTERN ( ^ rank1 rank2 )
DEFINE
rank1 AS rank_position = 1,
rank2 AS rank_position = 2
)
Which, for the sample data:
CREATE TABLE table_name (ID, SOME_DATE, RANK_POSITION) AS
SELECT 301, DATE '2021-12-01', 1 FROM DUAL UNION ALL
SELECT 301, DATE '2021-12-02', 2 FROM DUAL UNION ALL
SELECT 301, DATE '2021-12-03', 3 FROM DUAL UNION ALL
SELECT 649, DATE '2021-12-01', 1 FROM DUAL UNION ALL
SELECT 649, DATE '2021-12-02', 2 FROM DUAL UNION ALL
SELECT 649, DATE '2021-12-06', 3 FROM DUAL UNION ALL
SELECT 649, DATE '2021-12-08', 4 FROM DUAL UNION ALL
SELECT 649, DATE '2021-12-11', 5 FROM DUAL UNION ALL
SELECT 758, DATE '2021-12-12', 1 FROM DUAL UNION ALL
SELECT 758, DATE '2021-12-22', 2 FROM DUAL;
All output:
ID FIRST_IN_RANK_DATE SECOND_IN_RANK_DATE 301 2021-12-01 00:00:00 2021-12-02 00:00:00 649 2021-12-01 00:00:00 2021-12-02 00:00:00 758 2021-12-12 00:00:00 2021-12-22 00:00:00
db<>fiddle here