Использование UNPIVOT
с аналитической функцией LAG
или LEAD
сделает это при сканировании одной таблицы:
SQL Fiddle
Oracle11g Настройка схемы R2 :
create table TBL_CHILDREN ( parent_id, child_id, start_date, end_date )AS
SELECT 57, 1, DATE '2017-01-01', DATE '9999-12-31' FROM dual UNION ALL
SELECT 57, 2, DATE '2017-03-01', DATE '2017-05-31' FROM dual UNION ALL
SELECT 57, 3, DATE '2017-04-01', DATE '2017-10-31' FROM dual;
Запрос 1 :
SELECT *
FROM (
SELECT PARENT_ID,
DT AS start_date,
LEAD( DT ) OVER ( PARTITION BY parent_id ORDER BY DT ) AS end_date
FROM TBL_CHILDREN
UNPIVOT( dt FOR start_end IN ( start_date, end_date ) )
)
WHERE end_date IS NOT NULL
Результаты :
| PARENT_ID | START_DATE | END_DATE |
|-----------|----------------------|----------------------|
| 57 | 2017-01-01T00:00:00Z | 2017-03-01T00:00:00Z |
| 57 | 2017-03-01T00:00:00Z | 2017-04-01T00:00:00Z |
| 57 | 2017-04-01T00:00:00Z | 2017-05-31T00:00:00Z |
| 57 | 2017-05-31T00:00:00Z | 2017-10-31T00:00:00Z |
| 57 | 2017-10-31T00:00:00Z | 9999-12-31T00:00:00Z |
Запрос 2 , и он будет получать идентификаторы родителя и ребенка для каждого периода времени:
SELECT *
FROM (
SELECT parent_id,
( SELECT LISTAGG( child_id, ',' ) WITHIN GROUP ( ORDER BY child_id )
FROM TBL_CHILDREN c
WHERE u.dt >= c.START_DATE
AND u.dt < c.END_DATE ) AS child_ids,
DT AS start_date,
LEAD( DT ) OVER ( PARTITION BY parent_id ORDER BY DT ) AS end_date
FROM TBL_CHILDREN
UNPIVOT( dt FOR start_end IN ( start_date, end_date ) ) u
)
WHERE end_date IS NOT NULL
Результаты :
| PARENT_ID | CHILD_IDS | START_DATE | END_DATE |
|-----------|-----------|----------------------|----------------------|
| 57 | 1 | 2017-01-01T00:00:00Z | 2017-03-01T00:00:00Z |
| 57 | 1,2 | 2017-03-01T00:00:00Z | 2017-04-01T00:00:00Z |
| 57 | 1,2,3 | 2017-04-01T00:00:00Z | 2017-05-31T00:00:00Z |
| 57 | 1,3 | 2017-05-31T00:00:00Z | 2017-10-31T00:00:00Z |
| 57 | 1 | 2017-10-31T00:00:00Z | 9999-12-31T00:00:00Z |