即使缺少月份,我也需要所有24个月的数据

时间:2019-02-10 16:21:01

标签: sql oracle

即使缺少几个月,我也需要所有24个月的数据。

样本数据

 id     custname    reportdate   sales
 1        xx        31-JAN-17    1256
 1        xx        31-MAR-17    3456
 1        xx        30-JUN-17    5678
 1        xx        31-DEC-17    6785
 2        xx        31-JAN-17    1223
 2        xx        31-APR-17    3435
 2        xx        30-JUN-17    6777
 2        xx        31-DEC-17    9643

我需要什么作为输出

 id     custname    reportdate   sales
 1        xx        JAN-17       1256 
 1        xx        FEB-17       <null>
 1        xx        MAR-17       3456
 .....................................
 .....................................
 1        xx        DEC-17       6785

对于ID 2 ....

尝试了这种运气

select CUSTNAME, reportdate, sales from
(
select TRIM( LEADING '0' FROM TO_CHAR( statementdate, 'YYYY-MM') ) AS REPORTDATE mm, CUSTNAME
froM MYTABLE) SALES,
(
select to_char(date '2017-01-01' + numtoyminterval(level,'month'), 'mm') MonthName
--i actually need format as MON-Last 2 digit of year eg:JAN-17
from dual
connect by level <= 24) ALLMONTHS
where mm = MonthName(+)

也尝试过使用CTE,但我无法通过外部联接使用my_year.year_month CTE

my_year as (
       select date '2017-01-31' start_date,date '2018-12-31' end_date from dual
          )
   select  (to_char(add_months(trunc(start_date,'mm'),level - 1),'yyyy')||'-'||(to_char(add_months(trunc(start_date,'mm'),level - 1),'mm'))) year_month
     from  my_year
   connect by trunc(end_date,'mm') >= add_months(trunc(start_date,'mm'),level - 1);

select id, customername, reportdate, sales, 
TRIM( LEADING '0' FROM TO_CHAR( reportdate, 'YYYY-MM') ) AS stmntdate
from my_oracle_tbl a
where a.stmntdate = my_year.year_month (+)

还按照@Littlefoot的建议尝试了此操作,该方法不起作用

 WITH mydates AS (
    select LAST_DAY(add_months(date '2017-01-01', level - 1)) as mth, min_id,min_custname
  from (
  select min(id) as min_id, min(CUSTNAME) as min_custname
  from my_oracle_tbl 
  )
  connect by level <= 24)
  select
  nvl(t.id, a.min_id)id,
  nvl(t.CUSTNAME,a.min_custname)CUSTNAME, a.mth, t.sales
   from mydates a left join my_oracle_tbl t on a.mth= LAST_DAY(t.reporttdate)
  where
  t.id=2

;

3 个答案:

答案 0 :(得分:0)

这是一个例子;看看是否有帮助。它显示12个月(您将在第21行中将其替换为24个月)。

SQL> alter session set nls_date_format = 'dd.mm.yyyy';

Session altered.

SQL> with test (id, custname, reportdate, sales) as
  2        (select 1, 'xx', date '2017-01-31', 1256 from dual union all
  3         select 1, 'xx', date '2017-03-31', 3456 from dual union all
  4         select 1, 'xx', date '2017-06-30', 5678 from dual union all
  5         --
  6         select 2, 'xx', date '2017-03-31', 1223 from dual union all
  7         select 2, 'xx', date '2017-07-31', 3435 from dual union all
  8         select 2, 'xx', date '2017-09-30', 6777 from dual
  9        ),
 10      all_dates as
 11        (select add_months(min_repdate, column_value - 1) c_mon,
 12                min_id,
 13                min_custname
 14        from (select min(reportdate) min_repdate,
 15                     id min_id,
 16                     min(custname) min_custname
 17              from test
 18              group by id
 19             ),
 20             table(cast(multiset(select level from dual
 21                                 connect by level <= 12
 22                                 ) as sys.odcinumberlist))
 23       )
 24     select nvl(t.id, a.min_id) id,
 25            nvl(t.custname, a.min_custname) custname,
 26            a.c_mon,
 27            t.sales
 28     from all_dates a left join test t on a.min_id = t.id and a.c_mon = t.reportdate
 29     order by id, a.c_mon;

        ID CU C_MON           SALES
---------- -- ---------- ----------
         1 xx 31.01.2017       1256
         1 xx 28.02.2017
         1 xx 31.03.2017       3456
         1 xx 30.04.2017
         1 xx 31.05.2017
         1 xx 30.06.2017       5678
         1 xx 31.07.2017
         1 xx 31.08.2017
         1 xx 30.09.2017
         1 xx 31.10.2017
         1 xx 30.11.2017
         1 xx 31.12.2017
         2 xx 31.03.2017       1223
         2 xx 30.04.2017
         2 xx 31.05.2017
         2 xx 30.06.2017
         2 xx 31.07.2017       3435
         2 xx 31.08.2017
         2 xx 30.09.2017       6777
         2 xx 31.10.2017
         2 xx 30.11.2017
         2 xx 31.12.2017
         2 xx 31.01.2018
         2 xx 28.02.2018

24 rows selected.

SQL>

答案 1 :(得分:0)

您可以使用一些老式的技巧(将所有元素与ADD_MONTHS功能和总和结合在一起):

select id, custname,month, 
decode(sum(sales),0,null,sum(sales)) sales from
(select id, custname,  to_char(reportdate, 'mon-rrrr') 
 month,sales from my_oracle_tbl  
 UNION ALL
 select a.*,b.*,0 sales from
 (select distinct id, custname from my_oracle_tbl) a, 
 (
      select to_char(sysdate,'mon')||'-2017' month from dual
      UNION ALL
      select ,to_char(add_months(sysdate,1),'mon')||'-2017' month from dual
      UNION ALL
      select ,to_char(add_months(sysdate,2),'mon')||'-2017' from dual
      .......
      UNION ALL
      select ,to_char(add_months(sysdate,11),'mon')||'-2017' from dual) b
 )
 group by id, custname,month;

答案 2 :(得分:0)

这就是我想到的,您是否有任何担忧?有没有更好的方法来写这个?我需要从最低日期到最大日期获得订单?我怎么能做到这一点。截至目前,它重复这样的订单12-2018,12-2017,11-2018,11-2017。我想先2017年,然后2018年

select CUSTNAME, reportdate, sum(sales), mth
from (  select to_char(add_months(date '2017-01-01', level - 1), 'mmyyyy') mth 
  from dual 
  connect by level <= 24)mo
  left outer join oracle_tbl dc on mo.mth = to_char(reportdate, 'mmyyyy')
      group by CUSTNAME, reportdate,mth
    order by mth