考虑一个随时间跟踪喜欢的颜色的表格。
drop table favourites;
create table favourites(
person_id varchar2(10) not null
,valid_from date not null
,valid_to date
,color varchar2(10) not null
,constraint favourites_pk primary key(person_id, valid_from)
);
insert into favourites values('Ronnie', date '1979-09-12', null, 'Green');
insert into favourites values('Ronnie', date '2000-01-01', date '2016-12-31', 'Blue');
commit;
该表列出了' Ronnie'喜欢绿色从1979-09-12然后从2000-01-01他喜欢蓝色。当Ronnie在2017年的第一天醒来时,他不再喜欢Blue了。
我需要用一次性脚本清理一张桌子,但我仍然坚持上面显示的特定情况。到目前为止,最好的想法是根据valid_from日期重新计算valid_to日期,但在这种情况下,我实际上会破坏信息:如下所示" green"不再是2017-01-01的最爱,它应该是。
select person_id
,valid_from
,valid_to
,lead(valid_from,1) over(partition by person_id order by valid_from)-1 as valid_to2
,color
from favourites t;
PERSON_ID VALID_FROM VALID_TO NEW_VALID_TO COLOR
--------- ---------- ---------- ------------ ------
Ronnie 1979-09-12 null 1999-12-31 Green
Ronnie 2000-01-01 2016-12-31 null Blue
如何生成aditional记录,以便最终结果为:
PERSON_ID VALID_FROM VALID_TO COLOR
--------- ---------- ---------- ------
Ronnie 1979-09-12 1999-12-31 Green
Ronnie 2000-01-01 2016-12-31 Blue
Ronnie 2017-01-01 null Green
修改
valid_to
日期背后没有合理的逻辑。这是用户所投入的内容,因此存在各种疯狂的重叠。 null表示" forever"或9999-12-31,如果它更容易理解。我想通过创建另一个表来修复此设计,但首先我需要一种方法来修复旧数据。
也许以这种方式看待它会更容易。
Green |---------------------------------->
Blue |------|
我通过计算新的valid_to日期修复重叠,我销毁信息:
Green |--------|
Blue |------|
必须像这样修复:
Green |--------|
Blue |------|
Green |-------->
原始数据集中的问题仅显示第二个查询(由于重叠)。另外两个显示正确的结果。
select *
from favourites
where (date '1995-01-01' >= valid_from)
and (date '1995-01-01' <= valid_to or valid_to is null);
select *
from favourites
where (date '2015-01-01' >= valid_from)
and (date '2015-01-01' <= valid_to or valid_to is null);
select *
from favourites
where (date '2025-01-01' >= valid_from)
and (date '2025-01-01' <= valid_to or valid_to is null);
答案 0 :(得分:0)
如果您的示例是您关注的一种重叠类型,那么您可以使用union all
处理此问题。我想这是你想要的查询:
select person_id, color, valid_from,
coalesce(valid_to, lead(valid_from) over (partition by person_id order by valid_from)-1) as valid_to2
from favourites t
union all
select person_id, color, valid_to + 1 as valid_from, NULL as valid_to
from favourites f
where valid_from is null and
exists (select 1 from favourites f2 where f2.person_id = f.person_id and f2.valid_from > f.valid_from);
作为唯一的类型,我的意思是只有一个valid_from
是NULL
,并且记录不会重叠。如果您有更多生成问题,那么您应该询问另一个问题,并提供适当的数据和解释如何处理重叠。
答案 1 :(得分:0)
获取当前行的结束日期很简单(从下一行减去1天&#39; date_from)。但是,您应该生成一个需要union all
的新行。此外,默认颜色选择为valid_to
为null
的行中的颜色。 (如果不是这样的话,你需要改变cte中的逻辑)。
WITH CTE AS
(SELECT PERSON_ID,
COLOR,
VALID_FROM,
ROW_NUMBER() OVER(PARTITION BY PERSON_ID ORDER BY VALID_FROM DESC) AS RNUM,
COALESCE(VALID_TO, LEAD(VALID_FROM) OVER (PARTITION BY PERSON_ID
ORDER BY VALID_FROM)-1) AS VALID_TO_NEW,
MAX(CASE WHEN VALID_TO IS NULL THEN COLOR END)
OVER(PARTITION BY PERSON_ID ORDER BY VALID_FROM) AS DEFAULT_COLOR
FROM FAVOURITES)
SELECT PERSON_ID,
VALID_FROM,
VALID_TO_NEW,
COLOR
FROM CTE
UNION ALL
--Generates a new last row with the default color if it exists
SELECT PERSON_ID,
VALID_TO_NEW+1,
NULL,
DEFAULT_COLOR
FROM CTE
WHERE RNUM=1