2017-02-23 4 views
1

나는 아래에 달력 쿼리와 테이블이 있습니다. 회원의 StartDate 및 종료일이 있습니다. 또한 내 캘린더 테이블에서 startDate를 기반으로 "Weekof"를 캡처했습니다. 그 weekof 중 언제라도 회원이 활동하고 있다면 그것을 포착하고 싶습니다. 예상 결과를 확인하십시오.날짜 범위를 기반으로 여러 행 만들기

SELECT DISTINCT 
    --CA.CALENDAR_DATE, 
     TO_CHAR(CALENDAR_DATE,'MM/DD/YYYY') AS CALENDAR_DATE         
      TO_CHAR(NEXT_DAY(CALENDAR_DATE, 'Monday') - 7, 'MM/DD/YY-') || 
     TO_CHAR(NEXT_DAY(CALENDAR_DATE, 'Monday') - 1, 'MM/DD/YY') AS WEEK_OF_YEAR, 

     ROW_NUMBER() OVER (ORDER BY CALENDAR_DATE) AS MasterCalendar_RNK 

    FROM CALENDAR CA 
    WHERE 1=1 
     --AND CA.CALENDAR_DATE BETWEEN ADD_MONTHS(TRUNC(SYSDATE), -12) AND TRUNC(SYSDATE) 
     --AND CA.CALENDAR_DATE BETWEEN TRUNC(SYSDATE) -5 AND TRUNC(SYSDATE) 
     ORDER BY TO_DATE(CALENDAR_DATE,'MM/DD/YYYY') DESC 

Member StartDate EndDate  
    A   1/31/17  
    B   2/1/17  2/15/17 

예상 출력 :

Member StartDate EndDate Week_Of_Year  Active 
    A   1/31/17     1/30/17-2/5/17  1 
    A   1/31/17     2/6/17-2/12/17  1 
    A   1/31/17     2/13/17-2/19/17  1 
    B   2/1/17  2/15/17  1/30/17/2/5/17  1 
    B   2/1/17  2/15/17  2/6/17-2/12/17  1 
    B   2/1/17  2/15/17  2/13/17-2/19/17  1 

현재 쿼리 : 달력 쿼리는 현재 문자열을 생성하기 때문에

WITH MASTER_CALENDAR AS (
SELECT TRUNC(SYSDATE) + 1 - LEVEL , A.CALENDAR_DATE 
FROM (SELECT C.CALENDAR_DATE FROM MST.CALENDAR C WHERE 1=1 AND C.CALENDAR_DATE > SYSDATE-30 AND C.CALENDAR_DATE < SYSDATE) A 

WHERE 1=1 

CONNECT BY LEVEL <= 1 --NEED TO UPDATE? 

ORDER BY A.CALENDAR_DATE DESC  
         ), 

ActiveMembers AS (
SELECT H.CLT_CLT_PGMID, H.START_DT 

    ,CASE WHEN TRUNC(H.END_DT) = '1-JAN-3000' 
    THEN SYSDATE 
    ELSE TO_DATE(H.END_DT) 
    END AS END_DT 

FROM H 
WHERE 1=1 
    AND H.CLT_CLT_PGMID IN ('1','2','3') 
         ) 

SELECT CLT_CLT_PGMID, STARTDATE, ENDDATE, WEEK_OF_YEAR, ACTIVE -- but not week_start 
FROM (
SELECT DISTINCT A.CLT_CLT_PGMID, 
    TO_CHAR(A.START_DT, 'MM/DD/YY') AS STARTDATE, 
    TO_CHAR(A.END_DT, 'MM/DD/YY') AS ENDDATE, 
    NEXT_DAY(CAL.CALENDAR_DATE, 'Monday') - 7 AS WEEK_START, -- for ordering later 
    TO_CHAR(NEXT_DAY(CAL.CALENDAR_DATE, 'Monday') - 7, 'MM/DD/YY-') || 
    TO_CHAR(NEXT_DAY(CAL.CALENDAR_DATE, 'Monday') - 1, 'MM/DD/YY') AS WEEK_OF_YEAR, 
    1 AS ACTIVE 

FROM ActiveMembers A 
    INNER JOIN MASTER_CALENDAR CAL ON CAL.CALENDAR_DATE BETWEEN A.START_DT AND A.END_DT 
                    --BETWEEN TO_CHAR(A.START_DT,'MM/DD/YYYY') AND COALESCE(A.END_DT,(SYSDATE))                 
            ) 
WHERE 1=1 

ORDER BY 
CLT_CLT_PGMID , STARTDATE, ENDDATE, WEEK_START 
        ; 

답변

1

, 돌아갈 간단 할 것 캘린더 테이블에, joi N 귀하의 회원/날짜 테이블이, 그리고 주 범위 문자열 재생 :

with calendar(calendar_date) as (
    select trunc(sysdate) + 1 - level from dual connect by level <= 42 
), 
mytable (member, startdate, enddate) as (
    select cast('A' as varchar2(6)), date '2017-01-31', cast (null as date) from dual 
    union all select cast('B' as varchar2(6)), date '2017-02-01', date '2017-02-15' from dual 
) 
select member, startdate, enddate, week_of_year, active -- but not week_start 
from (
    select distinct m.member, 
     to_char(m.startdate, 'MM/DD/YY') as startdate, 
     to_char(m.enddate, 'MM/DD/YY') as enddate, 
     next_day(c.calendar_date, 'Monday') - 7 as week_start, -- for ordering later 
     to_char(next_day(c.calendar_date, 'Monday') - 7, 'MM/DD/YY-') || 
     to_char(next_day(c.calendar_date, 'Monday') - 1, 'MM/DD/YY') as week_of_year, 
     1 as active 
    from mytable m 
    join calendar c 
    on c.calendar_date between m.startdate and coalesce(m.enddate, trunc(sysdate)) 
) 
order by member, startdate, enddate, week_start; 

:

열팽창 계수와는 및 회원 데이터 (지금의 지난 몇 주 동안 날짜와) 캘린더 테이블을 나타내는

MEMBER STARTDAT ENDDATE WEEK_OF_YEAR   ACTIVE 
------ -------- -------- ----------------- ---------- 
A  01/31/17   01/30/17-02/05/17   1 
A  01/31/17   02/06/17-02/12/17   1 
A  01/31/17   02/13/17-02/19/17   1 
A  01/31/17   02/20/17-02/26/17   1 
B  02/01/17 02/15/17 01/30/17-02/05/17   1 
B  02/01/17 02/15/17 02/06/17-02/12/17   1 
B  02/01/17 02/15/17 02/13/17-02/19/17   1 

얻을 당신은 끝이 - 날짜와 구성원에 대한 상한을 지정하지 않은, 그래서 나는 coalesce()을 통해, 오늘날 사용했습니다.

내부 쿼리는 주 범위 문자열을 사용할 수 없기 때문에 주문할 때만 필요하며 독자적으로 주 시작을 보지 않으려합니다. 선택하지 않은 필드로는 별개 및 순서를 사용할 수 없습니다.

+0

캘린더의 마지막 30 일만 필요하므로 결과에 대한 하위 쿼리를 추가했습니다. 연결 기준에 익숙하지 않지만 수준에 따라 연결을 <= 42에서 <= 1으로 변경했습니다.이 기능이 무엇인지 잘 모르겠습니다. 당신은 설명 할 수 있었고 쿼리는 예제에 대해 작동하지만 어떻게 해석 할 수 있습니까? – John

+0

내 질문에 귀하의 대답에 따라 현재 질문이 표시됩니다. – John

+0

@ John - 42는 connect-subquery가 반환하는 행 수를 제한합니다. 그 숫자와 특별한 관련성은 없으며, 예제 데이터에 대해 적어도 충분한 날짜를 생성하는 것을 선택했습니다. 해당 하위 쿼리를 자체적으로 실행하면 개별 날짜 범위가 생성됩니다. 42를 30으로 변경하면 마지막 42 개가 아닌 지난 30 일이 생성됩니다 (1로 변경하면 1 개의 날짜 만 표시됨). 하지만 캘린더 테이블에서 날짜를 가져 오는 경우 연결 필요가 전혀 없습니다. (저는 CTE가 귀하의 실제 데이터를 대표한다고 말했습니다.) –

1

Alex와 비슷한 방식으로이 작업을 수행하지만 약간 다릅니다. 월요일부터 시작해서 몇 주가 지나면, TRUNC(dt, 'iw')을 사용하여 지정된 날짜의 ISO 시작 (월요일로 정의 됨)을 가져옵니다. 그럼 난과 같이, 테이블에 가입하기 전에 사람들의 고유 한 값을 얻을 것 : 알렉스처럼

with calendar as (select trunc(sysdate) - level + 1 calendar_date 
        from dual 
        connect by level <= 50), 
    your_table as (select 'A' member, date '2017-01-31' startdate, NULL enddate from dual union all 
        select 'B' member, date '2017-02-01' startdate, date '2017-02-15' enddate from dual) 
select yt.member, 
     yt.startdate, 
     yt.enddate, 
     to_char(c.week_start, 'mm/dd/yyyy') 
     || ' - ' || to_char(c.week_start + 6, 'mm/dd/yyyy') week_of_year, 
     1 as active 
from your_table yt 
     inner join (select distinct trunc(cl.calendar_date, 'iw') week_start 
        from calendar cl) c on c.week_start <= nvl(yt.enddate, SYSDATE) AND c.week_start + 6 >= yt.startdate 
order by yt.member, 
     c.week_start; 
MEMBER STARTDATE ENDDATE WEEK_OF_YEAR    ACTIVE 
------ ---------- ---------- ----------------------- ---------- 
A  01/31/2017   01/30/2017 - 02/05/2017   1 
A  01/31/2017   02/06/2017 - 02/12/2017   1 
A  01/31/2017   02/13/2017 - 02/19/2017   1 
A  01/31/2017   02/20/2017 - 02/26/2017   1 
B  02/01/2017 02/15/2017 01/30/2017 - 02/05/2017   1 
B  02/01/2017 02/15/2017 02/06/2017 - 02/12/2017   1 
B  02/01/2017 02/15/2017 02/13/2017 - 02/19/2017   1 

을, 당신의 널 (null) ENDDATE 오늘 (SYSDATE)까지 실행 가정했습니다. 그러나 B 멤버의 결과를 보면 1 월 30 일이 2 월 1 일과 15 일 사이가 아니기 때문에 중복되는 범위를 찾고있는 것처럼 보입니다. 따라서 그에 맞게 조인 절이 수정되었습니다. 이로 인해 구성원 A에 대한 추가 행이 생기므로 sysdate의 이전 일요일까지 널 enddate를 실행하려고합니까? 확실하지 않다. 당신이 필요하다면 너는 너 자신을 교정 할 수있을 것이라고 확신한다.

관련 문제