ORACLE SQL: Fill in missing dates

后端 未结 3 484
逝去的感伤
逝去的感伤 2020-12-04 02:42

I have the following code which gives me production dates and production volumes for a thirty day period.

select 
(case when trunc(so.revised_due_date) <=         


        
相关标签:
3条回答
  • 2020-12-04 03:17

    You can get the 30-day period from SYSDATE as follows (I assume you want to include SYSDATE?):

    WITH mydates AS (
        SELECT TRUNC(SYSDATE) - 1 + LEVEL AS due_date FROM dual
       CONNECT BY LEVEL <= 31
    )
    

    Then use the above to do a LEFT JOIN with your query (perhaps not a bad idea to put your query in a CTE as well):

    WITH mydates AS (
        SELECT TRUNC(SYSDATE) - 1 + LEVEL AS due_date FROM dual
       CONNECT BY LEVEL <= 31
    ), myorders AS (
        select 
        (case when trunc(so.revised_due_date) <= trunc(sysdate) 
            then trunc(sysdate) else trunc(so.revised_due_date) end) due_date, 
        (case 
            when (case when sp.pr_typ in ('VV','VD') then 'DVD' when sp.pr_typ in ('RD','CD') 
            then 'CD' end) = 'CD' 
            and  (case when so.tec_criteria in ('PI','MC') 
            then 'XX' else so.tec_criteria end) = 'OF'
            then sum(so.revised_qty_due)
        end) CD_OF_VOLUME
        from shop_order so
        left join scm_prodtyp sp
        on so.prodtyp = sp.prodtyp
        where so.order_type = 'MD' 
        and so.plant = 'W' 
        and so.status_code between '4' and '8' 
        and trunc(so.revised_due_date) <= trunc(sysdate)+30
        group by trunc(so.revised_due_date), so.tec_criteria, sp.pr_typ
        order by trunc(so.revised_due_date)
    )
    SELECT mydates.due_date, myorders.cd_of_volume
      FROM mydates LEFT JOIN myorders
        ON mydates.due_date = myorders.due_date;
    

    If you want to show a zero on "missing" dates instead of a NULL, use COALESCE(myorders.cd_of_volume, 0) AS cd_of_volume above.

    0 讨论(0)
  • 2020-12-04 03:33

    what you can do is this : creating a new table with all the days you need .

    WITH DAYS AS
    (SELECT TRUNC(SYSDATE) - ROWNUM DDD
     FROM ALL_OBJECTS
     WHERE ROWNUM < 365)
    SELECT
      DAYS.DDD
    FROM
    
      DAYS;
    

    then full outer join between thoes table :

    select  DUE_DATE ,   CD_OF_VOLUME , DDD
    from (
        select 
        (case when trunc(so.revised_due_date) <= trunc(sysdate) 
            then trunc(sysdate) else trunc(so.revised_due_date) end) due_date, 
        (case 
            when (case when sp.pr_typ in ('VV','VD') then 'DVD' when sp.pr_typ in ('RD','CD') 
            then 'CD' end) = 'CD' 
            and  (case when so.tec_criteria in ('PI','MC') 
            then 'XX' else so.tec_criteria end) = 'OF'
            then sum(so.revised_qty_due)
        end) CD_OF_VOLUME
        from shop_order so
        left join scm_prodtyp sp
        on so.prodtyp = sp.prodtyp
        where so.order_type = 'MD' 
        and so.plant = 'W' 
        and so.status_code between '4' and '8' 
        and trunc(so.revised_due_date) <= trunc(sysdate)+30
        group by trunc(so.revised_due_date), so.tec_criteria, sp.pr_typ
        order by trunc(so.revised_due_date)
    )  full outer join   NEW_TABLE new on (    new .DDD =  DUE_DATE     )
      where new .DDD between   /* */   AND   /* */   /*   pick your own limit) */
    
    0 讨论(0)
  • 2020-12-04 03:36

    you can get the gaps by using connect by and a left join:

    assuming your schema is:

    create table tbl(DUE_DATE date, CD_OF_VOLUME float);
    insert into tbl values(to_date('14/04/2015','DD/MM/YYYY'),35267.00);
    insert into tbl values(to_date('15/04/2015','DD/MM/YYYY'),71744.00); 
    insert into tbl values(to_date('16/04/2015','DD/MM/YYYY'),20268.00); 
    insert into tbl values(to_date('17/04/2015','DD/MM/YYYY'),35156.00); 
    insert into tbl values(to_date('18/04/2015','DD/MM/YYYY'),74395.00); 
    insert into tbl values(to_date('19/04/2015','DD/MM/YYYY'),3636.00); 
    insert into tbl values(to_date('21/04/2015','DD/MM/YYYY'),5522.00);
    insert into tbl values(to_date('22/04/2015','DD/MM/YYYY'),15502.00);
    insert into tbl values(to_date('04/05/2015','DD/MM/YYYY'),10082.00);
    

    you can say:

    with cte as
    (
      select (select min(DUE_DATE)-1 from tbl)+ level as dt
      from dual
      connect by level <= (select max(DUE_DATE)-min(DUE_DATE) from tbl)
    )
    select to_char(c.dt,'DD/MM/YYYY') gap,null volume 
    from cte c
    left join tbl t on c.dt=t.DUE_DATE
    where t.DUE_DATE is null
    order by c.dt
    

    Result:

    GAP         VOLUME
    20/04/2015  (null)
    23/04/2015  (null)
    24/04/2015  (null)
    25/04/2015  (null)
    26/04/2015  (null)
    27/04/2015  (null)
    28/04/2015  (null)
    29/04/2015  (null)
    30/04/2015  (null)
    01/05/2015  (null)
    02/05/2015  (null)
    03/05/2015  (null)
    

    Notice: you can implement this in your original query, one simplest way is to wrap your query and use it as a subquery instead of tbl in above code snippet.

    0 讨论(0)
提交回复
热议问题