3

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) <= 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)

The problem I have is where there is a date with no production planned, the date wont appear on the report. Is there a way of filling in the missing dates.

i.e. the current report shows the following ...

DUE_DATE    CD_OF_VOLUME 
14/04/2015     35,267.00 
15/04/2015     71,744.00 
16/04/2015     20,268.00 
17/04/2015     35,156.00 
18/04/2015     74,395.00 
19/04/2015      3,636.00 
21/04/2015      5,522.00
22/04/2015     15,502.00
04/05/2015     10,082.00

Note: missing dates (20/04/2015, 23/04/2015 to 03/05/2015)

Range is always for a thirty day period from sysdate. How do you fill in the missing dates? Do you need some kind of calendar table?

Thanks

1

3 Answers 3

5

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.

Sign up to request clarification or add additional context in comments.

Comments

1

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) */

Comments

1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.