2017-02-01 3 views
1

시간이 지남에 따라 선호하는 색상을 추적하는 표를 고려하십시오. 겹치기 정리 유효 기간 - 유효 기간이

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; 

은 '로니'1979년 9월 12일에서 녹색 좋아하고 2000-01-01에서 그는 파란색 좋아한다고. Ronnie가 2017 년 첫날에 깨어 났을 때 그는 더 이상 Blue를 좋아하지 않습니다.

일회성 스크립트로 표를 정리해야하지만 위의 특정 사례가 맞지 않습니다. 지금까지 가장 좋은 아이디어는 valid_to 날짜를 valid_from 날짜를 기준으로 다시 계산하는 것이지만이 경우 실제로 정보를 파괴합니다. 아래에서 볼 수있는 것처럼 "녹색"은 더 이상 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 

는 어떻게이 추가적으로 기록을 생성 할 수 있습니다 다음 valid_to 날짜 뒤에 어떤 합리적인 논리가 없다

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 

편집. 그것은 사용자가 넣은 것이므로 모든 종류의 미친 오버랩이 존재합니다. null은 "영원히"또는 9999-12-31을 의미하므로 이해하기 쉽습니다. 다른 테이블을 만들어이 디자인을 수정하고 싶지만, 먼저 이전 데이터를 수정해야합니다.

아마도 이런 식으로 보는 것이 더 쉽습니다.

그것은 갖는다
Green |--------| 
Blue   |------| 

이렇게 고정되도록 :

Green |----------------------------------> 
Blue   |------| 

제가 새로운 valid_to 날짜를 계산하여 중복 수정 I 정보를 파괴

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

이 오버랩 단지 예는? –

+1

새로 삽입 한 행의 색상이 녹색이어야하는 이유는 무엇입니까? null 일 수 있습니까? –

+0

그가 2017 년에 다시 녹색을 좋아하기 시작한 것을 어떻게 알 수 있습니까? 어딘가에 기본 규칙이 있습니까? – tbone

답변

0

, 당신은 union all와 함께이 문제를 처리 할 수 ​​있습니다. 나는 단지 하나의 valid_fromNULL하고 기록 그렇지 않으면 중복되지 않는 것을 의미하는 유일한 유형으로

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); 

:이 당신이 원하는 쿼리라고 생각합니다. 더 많은 질문이있는 경우 적절한 데이터와 함께 겹쳐서 무엇을해야하는지에 대한 설명을하여 다른 질문을해야합니다.

0

현재 행의 종료일을 얻는 것이 쉽습니다 (다음 행의 date_from에서 1 일 빼기). 그러나 union all이 필요한 새 행을 생성해야합니다. 또한 기본 색상은 valid_tonull 인 행에서 선택됩니다. (케이스가 아닌 경우 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 

Sample Demo