繁体   English   中英

从多行中删除Null; 创建[开始]和[结束]列

[英]Remove Nulls from multiple rows; create [Start] and [End] columns

我正在尝试创建一个表,该表具有按周开始和结束的列,并且不与月份转换重叠。 以2016年1月为例,我希望结果看起来像:

 Start      End
 1/1/2016   1/2/2016
 1/3/2016   1/9/2016
 1/10/2016  1/16/2016
 1/17/2016  1/23/2016
 1/24/2016  1/30/2016
 1/31/2016  1/31/2016  

我现在通过查询得到的是(我希望第二列和第三列中的记录相应地对齐):

 DATES          Wk_START_END    MONTH_START_END
 1/1/2016                       1/1/2016
 1/2/2016       1/2/2016    
 1/3/2016       1/3/2016    
 1/4/2016       
 1/5/2016       
 1/6/2016       
 1/7/2016       
 1/8/2016       
 1/9/2016       1/9/2016    
 1/10/2016      1/10/2016   
 1/11/2016      
 1/12/2016      
 1/13/2016      
 1/14/2016      
 1/15/2016      
 1/16/2016      1/16/2016   
 1/17/2016      1/17/2016   
 1/18/2016      
 1/19/2016      
 1/20/2016      
 1/21/2016      
 1/22/2016      
 1/23/2016      1/23/2016   
 1/24/2016      1/24/2016   
 1/25/2016      
 1/26/2016      
 1/27/2016      
 1/28/2016      
 1/29/2016      
 1/30/2016      1/30/2016   
 1/31/2016      1/31/2016       1/31/2016

此刻的查询:

    SELECT trunc
      (sysdate, 'YEAR')+rownum-1 DATES
      --,to_char(trunc(sysdate,'YEAR') + rownum -1 ,'D') Day_Of_Wk

    , CASE
         WHEN to_char
             (trunc
             (sysdate, 'YEAR')+rownum-1, 'D') = '1' THEN trunc
                                                (sysdate, 'YEAR')+rownum-1
         WHEN to_char
             (trunc
             (sysdate, 'YEAR')+rownum-1, 'D') = '7' THEN trunc
                                                (sysdate, 'YEAR')+rownum-1
         ELSE NULL
      END Wk_Start_End
    , CASE
         WHEN trunc
             (sysdate, 'YEAR')+rownum-1 = TRUNC
             (trunc
             (sysdate, 'YEAR')+rownum-1, 'MONTH') THEN trunc
                                               (sysdate, 'YEAR')+rownum-1
         WHEN trunc
             (sysdate, 'YEAR')+rownum-1 = Add_months
             (TRUNC
             (trunc
             (sysdate, 'YEAR')+rownum-1, 'MONTH'), 1)-1 THEN trunc
                                                    (sysdate, 'YEAR')+rownum-1
      END Month_Start_end
FROM   all_objects
WHERE  trunc
     (sysdate, 'YEAR')+rownum <= Add_months
     (trunc
     (sysdate, 'YEAR'), 12)-1;

任何帮助表示赞赏。 谢谢!

您似乎想要带值的奇数行,以及下一个非空值。 我在想:

select dte as start_date, next_dte and end_date
from (select ao.*, rownum as seqnum, lead(dte) over (order by dates) as next_dte
      from ((select dates, Wk_START_END as dte from all_objects ao) union all
            (select dates, MONTH_START_END as dte from all_objects ao)
           ) t
      where dte is not null
     ) t
where mod(seqnum, 2) = 1;

这是一个查询,它将针对所有2016年日期执行此操作。 我希望您可以根据自己的目的进行推断。

基本方法是获取感兴趣范围内的所有日期(例如,2016年全年),然后按月/周分组。 然后获取每个组中的min()max()日期。

WITH dtes AS
       (SELECT TO_DATE ('01-JAN-2016') + ROWNUM - 1 dte
        FROM   DUAL
        CONNECT BY ROWNUM <= 365),
     dtes_grouped_by_month_week AS
       (SELECT dte,
               DENSE_RANK () OVER (PARTITION BY NULL ORDER BY TO_CHAR (dte, 'IYYY-MM'), TO_CHAR (dte, 'IW')) month_week
        FROM   dtes)
SELECT MIN (dte) start_date,
       MAX (dte) end_date
FROM   dtes_grouped_by_month_week
GROUP BY month_week
ORDER BY month_week;

UPDATE re:一周的第一天

看您的示例,您似乎希望星期日是一周的第一天,而不是星期一。 这在查询中很容易进行调整-只需在DENSE_RANKTO_CHAR函数中的日期上加上+1。

下面的查询从头开始-它不使用任何代码(或其输出)。 年和月在第一个CTE中进行硬编码(顶部的WITH子句中的子查询); 在您的应用程序中,您更有可能会排除第一个CTE(名为inputs ,并且会在first_date的定义中(也在WITH子句中)使ym成为绑定变量。

我使用了您的约定:一周从“一周的第一天”开始(在美国为星期日),到“一周的第七天”结束。 如果需要,可以通过NLS参数进行调整。

with 
     inputs ( y, m ) as (
       select 2016, 1 from dual
     ),
     first_date ( f_dt ) as (
       select to_date(to_char(y, '0009') || '-' || to_char(m, '09'), 'yyyy-mm') 
       from   inputs
     ),
     mth_dates ( dt ) as (
       select f_dt + level - 1 from first_date
       connect by level <= last_day(f_dt) - f_dt + 1
     ),
     start_dates ( dt, rn ) as (
       select dt, row_number() over (order by dt)
       from   ( select dt from mth_dates where to_char(dt, 'd') = '1'
                union
                select min(dt) from mth_dates )
     ),
     end_dates ( dt, rn ) as (
       select dt, row_number() over (order by dt)
       from   ( select dt from mth_dates where to_char(dt, 'd') = '7'
                union
                select max(dt) from mth_dates )
     )
select s.rn as week_nbr, s.dt as start_date, e.dt as end_date
from   start_dates s inner join end_dates e   on s.rn = e.rn;

  WEEK_NBR START_DATE  END_DATE
---------- ---------- ----------
         1 2016-01-01 2016-01-02
         2 2016-01-03 2016-01-09
         3 2016-01-10 2016-01-16
         4 2016-01-17 2016-01-23
         5 2016-01-24 2016-01-30
         6 2016-01-31 2016-01-31

添加在OP的要求:

要生成全年的开始日期和结束日期,可以使用以下查询。

with 
     inputs ( y ) as (
       select 2016 from dual
     ),
     first_date ( f_dt ) as (
       select to_date(to_char(y, '0009') || '-01-01', 'yyyy-mm-dd') 
       from   inputs
     ),
     year_dates ( dt ) as (
       select f_dt + level - 1 from first_date
       connect by level <= add_months(f_dt, 12) - f_dt
     ),
     start_dates ( dt, rn ) as (
       select dt, row_number() over (order by dt)
       from   ( select dt from year_dates where to_char(dt, 'd') = '1'
                                             or extract(day from dt) = 1 )
     ),
     end_dates ( dt, rn ) as (
       select dt, row_number() over (order by dt)
       from   ( select dt from year_dates where to_char(dt, 'd') = '7'
                                             or extract(day from dt + 1) = 1 )
     )
select s.dt as start_date, e.dt as end_date
from   start_dates s inner join end_dates e   on s.rn = e.rn;

进一步说明 :实际上,我比我更喜欢马修的回答。 他的解决方案只是将日期分为几个月和几周的适当“集合交集”,并在这些组上使用max()min() ,从而避免了连接的需要。 这是比我更好的解决方案。

为了完整起见,我在下面复制了Matthew的解决方案,但做了一些小的更改。

  • 首先,为了满足要求(并如Matthew所建议),我在dte中加1来按周形成组,因此,几周从星期日开始,到星期六结束。

  • 第二,正如我在对《马修答案》的评论中所建议的那样,我直接使用“月”和“周”来组成小组。 不需要dense_rank()

  • 第三,为了遵循良好的编码习惯,我在第一个CTE中向to_date()添加了一个明确的日期格式模型。

图片来源 :@Matthew McPeak

with dtes ( dte ) as (
         select to_date ('01-Jan-2016', 'dd-Mon-yyyy') + rownum - 1
         from   dual
         connect by rownum <= 366   -- 2016 is a leap year
     ),
     dtes_grouped_by_month_week ( dte, mth, wk ) as (
         select dte, to_char(dte, 'mm'), to_char(dte+1, 'iw')
         from   dtes
     )
select   min(dte) start_date, max(dte) end_date
from     dtes_grouped_by_month_week
group by mth, wk
order by start_date;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM