这是一张图片,描述了我使用的表格(TBL_CHILDREN)以及我想要实现的所需输出。
所需的表希望在相同的PARENT_ID下为每个新的活动CHILD_ID组合设置单独的行。因此,例如,从2017-01-01到2017-02-28只有CHILD_ID 1处于活动状态,因此所需表格的行跨越2017-01-01到2017-02-28。但是在2017-03-01 CHILD_ID 2也生效了,所以我需要一个新行来反映CHILD_ID 1和2同时处于活动状态的时间段。依此类推,直到我有一行描述CHILD_ID组合的每个时期。
以下是TBL_CHILDREN的一些代码:
WITH TBL_CHILDREN AS (SELECT 57 PARENT_ID, 1 CHILD_ID, TO_DATE('2017-01-01','YYYY-MM-DD') START_DATE, TO_DATE('9999-12-31','YYYY-MM-DD') END_DATE FROM dual UNION ALL
SELECT 57 PARENT_ID, 2 CHILD_ID, TO_DATE('2017-03-01','YYYY-MM-DD') START_DATE, TO_DATE('2017-05-31','YYYY-MM-DD') END_DATE FROM dual UNION ALL
SELECT 57 PARENT_ID, 3 CHILD_ID, TO_DATE('2017-04-01','YYYY-MM-DD') START_DATE, TO_DATE('2017-10-31','YYYY-MM-DD') END_DATE FROM dual)
SELECT *
FROM TBL_CHILDREN
答案 0 :(得分:2)
将UNPIVOT
与LAG
或LEAD
分析函数配合使用,可以在单个表扫描中执行此操作:
Oracle 11g 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
<强> Results 强>:
| 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 ,这将获得每个时间段的父ID和子ID:
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
<强> Results 强>:
| 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 |
答案 1 :(得分:1)
请查看this demo
WITH qqq AS (
SELECT * FROM TBL_CHILDREN
START WITH child_id = 1
CONNECT BY PRIOR parent_id = parent_id AND PRIOR child_id + 1 = child_id
)
SELECT * FROM (
SELECT PARENT_ID,
d as start_date,
lead(d) over (partition by PARENT_ID order by d ) - 1 as end_date
FROM (
SELECT PARENT_ID, start_date as d FROM qqq
UNION
SELECT PARENT_ID, end_date FROM qqq
)
)
WHERE end_date is not null
ORDER by PARENT_ID, start_date
;
| PARENT_ID | START_DATE | END_DATE |
|-----------|----------------------|----------------------|
| 57 | 2017-01-01T00:00:00Z | 2017-02-28T00:00:00Z |
| 57 | 2017-03-01T00:00:00Z | 2017-03-31T00:00:00Z |
| 57 | 2017-04-01T00:00:00Z | 2017-05-30T00:00:00Z |
| 57 | 2017-05-31T00:00:00Z | 2017-10-30T00:00:00Z |
| 57 | 2017-10-31T00:00:00Z | 9999-12-30T00:00:00Z |