根据日期范围创建多个行

时间:2017-02-23 12:34:34

标签: oracle11g date-range connect-by

我有一个日历查询和下表。我有一个成员的StartDate和结束日期。同样在我的日历表上,我根据startDate捕获了一个“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 个答案:

答案 0 :(得分: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

和Alex一样,我假设您的null enddate一直运行到今天(sysdate)。但是,查看成员B的结果,看起来你正在寻找一个重叠的范围(因为1月30日不是2月1日到15日之间),所以我相应地修改了我的连接条款。这会导致成员A的额外行,所以您可能希望在sysdate的上一个星期日之前运行null enddates?不确定。如果您需要,我确定您可以自行修改。