在日期范围内为每个月生成单独的行

时间:2014-07-16 13:41:53

标签: sql oracle plsql cursor reporting

基本上我有一行数据,例如:

ID -   Start_Date -  End_Date

------------------------------------

XXA   1/23/14        3/12/14

我希望在Start_DateEnd_Date之间为每个ID创建一行,例如:

ID -  Month -     Year

--------------------------

XXA  January      2014

XXA  February     2014

XXA  March         2014

这是最好和最有效的方法吗?我正在考虑使用游标,但是一旦创建了这个表,我就需要将其他表加入到这个表中。我是oracle的新手,在运行游标并创建临时表后,我不确定是否可以加入其他表。任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:1)

您可以使用CONNECT BY语法使用简单的行生成技术:

with sample_data as 
  (select 'XXA' id, to_date('1/23/14','MM/DD/RR') start_date, to_date('3/12/14','MM/DD/RR') end_date from dual)
select id, to_char(add_months(start_date,level - 1),'Month YYYY') date_column
from sample_data
connect by level <= extract(month from end_date) - extract(month from start_date) + 1;

修改 我相信,添加DISTINCT应允许跨行工作,尽管我有兴趣被证明是错误的。 编辑2 修改后的例子来处理多年(最初应该这样做)。 (参见示例http://sqlfiddle.com/#!4/9eecb/4097/0。)

with sample_data as 
  ( select 'XXA' id, to_date('1/23/14','MM/DD/RR') start_date, to_date('3/12/15','MM/DD/RR') end_date from dual union all    
    select 'XXB' id, to_date('4/12/14','MM/DD/RR') start_date, to_date('6/18/15','MM/DD/RR') end_date from dual )
select distinct 
  id,
  to_char(add_months(start_date,level - 1),'Month YYYY') date_column,
  add_months(start_date,level -1) sortkey
from sample_data
connect by level <= ceil(months_between(trunc(end_date,'MM'), trunc(start_date,'MM'))) + 1
order by id, sortkey;

在我的沙盒DB中,这会产生:

ID  DATE_COLUMN     SORT_COL
XXA January   2014  23-JAN-2014 00:00:00
XXA February  2014  23-FEB-2014 00:00:00
XXA March     2014  23-MAR-2014 00:00:00
XXB April     2014  12-APR-2014 00:00:00
XXB May       2014  12-MAY-2014 00:00:00
XXB June      2014  12-JUN-2014 00:00:00

答案 1 :(得分:0)

要获得预期结果,需要一些年月数据。我建议两种可能的方法来提供它:

  1. 创建一个包含所有可能年月的表格或视图;
  2. 创建一个表函数,仅返回所需的年月。
  3. 其他选项假设隐含生成年度数据,我认为这不是一个好的,作为一个明显的直接解决方案。

    第二个选项(理论上)可能在更大的输入数据上更快,但是我不推荐它,因为你没有提及性能,它比第一个更复杂。

    最简单易用的解决方案是:

    create table year (id int primary key);
        insert into year values (2014);
        insert into year values (2015);
        insert into year values (2016);
    
    
    create table month (id int primary key, name char(255));
        insert into month values (1, 'Jan');
        insert into month values (2, 'Feb');
        insert into month values (3, 'Mar');
        insert into month values (4, 'Apr');
        insert into month values (5, 'May');
        insert into month values (6, 'Jun');
        insert into month values (7, 'Jul');
        insert into month values (8, 'Aug');
        insert into month values (9, 'Sep');
        insert into month values (10, 'Oct');
        insert into month values (11, 'Nov');
        insert into month values (12, 'Dec');
    
    
    create table data (id char(15) primary key , start_date date, end_date date);
        insert into data 
          values ('XXA', to_date('1/23/14','MM/DD/RR'), to_date('3/12/14','MM/DD/RR'));
        insert into data
          values ('XXB', to_date('4/12/14','MM/DD/RR'), to_date('6/18/14','MM/DD/RR'));
    
    
    create or replace view calendar as
        select y.id*100 + m.id as id, y.id as year, m.name as month 
          from year y, month m;
    
    
    select d.id, c.month, c.year 
        from  calendar c, data d
        where c.id between to_char(d.start_date, 'yyyymm') 
                   and to_char(d.end_date, 'yyyymm');
    

    输出结果为:

    XXA|Jan|2014
    ---+---+----
    XXA|Feb|2014
    ---+---+----
    XXA|Mar|2014
    ---+---+----
    XXB|Apr|2014
    ---+---+----
    XXB|May|2014
    ---+---+----
    XXB|Jun|2014
    

    提前填写Year表非常重要,否则它将一直运行到2016年。