SQL trunc/group/order by dates (day/month/quarter/year) with sum skip dates with no data

前端 未结 3 401
温柔的废话
温柔的废话 2021-01-22 16:16

I involved in project where I need to build histogram by dates. Before me this done in Java code by tons of SQL queries to DB for each rectangles (date subregions).

I tr

3条回答
  •  野趣味
    野趣味 (楼主)
    2021-01-22 17:08

    My production code based on local guru advises and @Ben technique:

    
    -- generate sequence 1..N:
    SELECT level FROM dual CONNECT BY level <= 4;
    
    -- generates days:
    select to_date('01-01-2012','DD-MM-YYYY') + level - 1
      from dual
    connect by level <= to_date('31-12-2012','DD-MM-YYYY') - to_date('01-01-2012','DD-MM-YYYY') + 1;
    
    with dates as (
      select (to_date('01-01-2012','DD-MM-YYYY') + level - 1) as daterange
        from dual
        connect by level <= to_date('31-12-2012','DD-MM-YYYY') - to_date('01-01-2012','DD-MM-YYYY') + 1
      ) select sum(tbl.cnt) as summ, trunc(dates.daterange, 'DDD')
          from dates
               left outer join DATA_TBL tbl
            on trunc(tbl.inc_date, 'DDD') = trunc(dates.daterange, 'DDD')
          group by trunc(dates.daterange, 'DDD')
          order by trunc(dates.daterange, 'DDD');
    
    -- generates months:
    select ADD_MONTHS(to_date('01-01-2012','DD-MM-YYYY'), level - 1)
      from dual
    connect by level <= months_between(to_date('31-12-2012','DD-MM-YYYY'), to_date('01-01-2012','DD-MM-YYYY')) + 1;
    
    with dates as (
      select add_months(to_date('01-01-2012','DD-MM-YYYY'), level-1) as daterange
        from dual
        connect by level <= months_between(to_date('31-12-2012','DD-MM-YYYY'), to_date('01-01-2012','DD-MM-YYYY')) + 1
      ) select sum(tbl.cnt) as summ, trunc(dates.daterange, 'MM')
          from dates
               left outer join DATA_TBL tbl
            on trunc(tbl.inc_date, 'MM') = trunc(dates.daterange, 'MM')
          group by trunc(dates.daterange, 'MM')
          order by trunc(dates.daterange, 'MM');
    
    -- generates quarters:
    select ADD_MONTHS(to_date('01-01-2012','DD-MM-YYYY'), (level-1)*3)
      from dual
      connect by level <= months_between(to_date('31-12-2012','DD-MM-YYYY'), to_date('01-01-2012','DD-MM-YYYY'))/3 + 1;
    
    with dates as (
      select add_months(to_date('01-01-2012','DD-MM-YYYY'), (level-1)*3) as daterange
        from dual
        connect by level <= months_between(to_date('31-12-2012','DD-MM-YYYY'), to_date('01-01-2012','DD-MM-YYYY'))/3 + 1
      ) select sum(tbl.cnt) as summ, trunc(dates.daterange, 'Q')
          from dates
               left outer join DATA_TBL tbl
            on trunc(tbl.inc_date, 'Q') = trunc(dates.daterange, 'Q')
          group by trunc(dates.daterange, 'Q')
          order by trunc(dates.daterange, 'Q');
    
    -- generates years:
    select add_months(to_date('01-01-2007','DD-MM-YYYY'), (level-1)*12)
      from dual
      connect by level <= months_between(to_date('31-01-2012','DD-MM-YYYY'), to_date('01-01-2007','DD-MM-YYYY'))/12 + 1;
    
    with dates as (
      select add_months(to_date('01-01-2007','DD-MM-YYYY'), (level-1)*12) as daterange
        from dual
        connect by level <= months_between(to_date('31-01-2012','DD-MM-YYYY'), to_date('01-01-2007','DD-MM-YYYY'))/12 + 1
      ) select sum(tbl.cnt) as summ, trunc(dates.daterange, 'YYYY')
          from dates
               left outer join DATA_TBL tbl
            on trunc(tbl.inc_date, 'YYYY') = trunc(dates.daterange, 'YYYY')
          group by trunc(dates.daterange, 'YYYY')
          order by trunc(dates.daterange, 'YYYY');
    

    But connect by level is hack according to:

    • http://www.sqlsnippets.com/en/topic-11821.html (Gotchas. To Use PRIOR or Not to Use PRIOR, That is the Question)

提交回复
热议问题