I have a query below that I need to get a count where Incident Records = 0. The first level is a summary of the records it grabs to calculate totals. I tried using COUNT(INCIDENTS!='0') but it apparently is not working though it does not error out. How would I get this count? This is in Snowflake if that is a factor. The case statement: CASE WHEN SUM(INCIDENTS) = '0' THEN '0' ELSE COUNT(INCIDENTS!='0') END AS INCIDENTS Works but the 2nd line which references those Incidents seems to only give a count but not the result of the Case Statement before it:
SELECT DRIVER_NAME, DRIVER_ID, CSC, SUM(DISTINCT(OBSERVATIONS)) AS OBSERVATIONS, --SUM(DISTINCT(INCIDENTS)) AS INCIDENTS_SUM_DISTINCT,
--COUNT(INCIDENTS) AS INCIDENTS,
COUNT(INCIDENTS!='0'),
CASE WHEN SUM(INCIDENTS) = '0' THEN '0' ELSE COUNT(INCIDENTS!='0') END AS INCIDENTS,
(COUNT(INCIDENTS!='0') / SUM(DISTINCT(OBSERVATIONS))) * 100 AS FREQUENCY_PERCENT,
1 AS GOAL, (SUM(SIX_TEN_MPH) / SUM(DISTINCT(OBSERVATIONS))) * 100 AS SIX_TEN_PERCENT,
(SUM(ELEVEN_FIFTEEN_MPH) / SUM(DISTINCT(OBSERVATIONS))) * 100 AS ELEVEN_FIFTEEN_PERCENT,
(SUM(SIXTEEN_PLUS_MPH) / SUM(DISTINCT(OBSERVATIONS))) * 100 AS SIXTEEN_PLUS_PERCENT
--SPEED_LIMIT, SPEED, DIFFERENCE, REPORT_DATE, TIME,
FROM
(
SELECT A.DRIVER_NAME AS DRIVER_NAME, A.DRIVER_ID AS DRIVER_ID, C.TRC_TERMINAL AS CSC, A.OBSERVATIONS AS OBSERVATIONS,
A.INCIDENTS AS INCIDENTS, B.SPEED_LIMIT AS SPEED_LIMIT, B.SPEED AS SPEED, B.DIFFERENCE AS DIFFERENCE,
A.REPORT_DATE AS REPORT_DATE, B.TIME AS TIME,
CASE WHEN DIFFERENCE >= 6 AND DIFFERENCE <= 10 THEN '1' WHEN DIFFERENCE IS NULL THEN '0' ELSE '0' END AS SIX_TEN_MPH,
CASE WHEN DIFFERENCE > 10 AND DIFFERENCE <= 15 THEN '1' WHEN DIFFERENCE IS NULL THEN '0' ELSE '0' END AS ELEVEN_FIFTEEN_MPH,
CASE WHEN DIFFERENCE > 15 THEN '1' WHEN DIFFERENCE IS NULL THEN '0' ELSE '0' END AS SIXTEEN_PLUS_MPH
FROM "PROD"."PUBLIC"."SG_DRIVER_TREND" A
LEFT JOIN "PROD"."PUBLIC"."SG_DRIVER_INCIDENTS" B
ON A.DRIVER_ID = B.DRIVER_ID
LEFT JOIN "PROD"."PUBLIC"."TMW_TRACTORPROFILE" C
ON B.Vehicle = C.TRC_NUMBER
WHERE A.DRIVER_ID != ''
AND A.REPORT_DATE BETWEEN '2022-07-01' AND '2022-07-31'
AND B.TIME BETWEEN '2022-07-01' AND '2022-07-31'
AND SUBSTRING(B.TIME, 0, 10) <= A.REPORT_DATE -- Less than or equal to report date
AND SUBSTRING(B.TIME, 0, 10) > SUBSTRING(DATEADD(week,-1, A.REPORT_DATE), 0, 10) -- Greater than 1 week ago
UNION
--SELECT A.DRIVER_NAME AS DRIVER_NAME, A.DRIVER_ID AS DRIVER_ID, C.TRC_TERMINAL AS CSC, A.OBSERVATIONS AS OBSERVATIONS,
-- A.INCIDENTS AS INCIDENTS, B.SPEED_LIMIT AS SPEED_LIMIT, B.SPEED AS SPEED, B.DIFFERENCE AS DIFFERENCE,
-- A.REPORT_DATE AS REPORT_DATE, B.TIME AS TIME,
SELECT DISTINCT(A.DRIVER_NAME) AS DRIVER_NAME, A.DRIVER_ID AS DRIVER_ID,
C.TRC_TERMINAL AS CSC,
--'UPT' AS CSC,
A.OBSERVATIONS AS OBSERVATIONS,
'0' AS INCIDENTS, '0' AS SPEED_LIMIT, '0' AS SPEED, '0' AS DIFFERENCE,
A.REPORT_DATE AS REPORT_DATE, '' AS TIME,
'0' AS SIX_TEN_MPH,
'0' AS ELEVEN_FIFTEEN_MPH,
'0' AS SIXTEEN_PLUS_MPH
FROM "PROD"."PUBLIC"."SG_DRIVER_TREND" A
LEFT JOIN "PROD"."PUBLIC"."SG_DRIVER_INCIDENTS" B
ON A.DRIVER_ID = B.DRIVER_ID
-- AND SUBSTRING(B.TIME, 0, 10) <= A.REPORT_DATE -- Less than or equal to report date
-- AND SUBSTRING(B.TIME, 0, 10) > SUBSTRING(DATEADD(week,-1, A.REPORT_DATE), 0, 10) -- Greater than 1 week ago
INNER JOIN "PROD"."PUBLIC"."TMW_TRACTORPROFILE" C
ON B.Vehicle = C.TRC_NUMBER
WHERE NOT EXISTS (SELECT DRIVER_ID FROM "PROD"."PUBLIC"."SG_DRIVER_INCIDENTS" D
WHERE A.DRIVER_ID = D.DRIVER_ID
AND D.TIME BETWEEN '2022-07-01' AND '2022-07-31'
AND SUBSTRING(D.TIME, 0, 10) <= A.REPORT_DATE -- Less than or equal to report date
AND SUBSTRING(D.TIME, 0, 10) > SUBSTRING(DATEADD(week,-1, A.REPORT_DATE), 0, 10) -- Greater than 1 week ago
)
AND A.DRIVER_ID != '' AND A.INCIDENTS = '0'
AND A.REPORT_DATE BETWEEN '2022-07-01' AND '2022-07-31'
--AND B.DRIVER_ID IS NULL --<-- For LEFT JOIN
ORDER BY DRIVER_ID
)
--WHERE INCIDENTS != 0
GROUP BY DRIVER_ID, DRIVER_NAME, CSC
ORDER BY DRIVER_ID
This line:
CASE WHEN SUM(INCIDENTS) = '0' THEN '0' ELSE COUNT(INCIDENTS!='0') END AS INCIDENTS seems to give me the correct number of incidents but when I try and copy it into this line as the Incident Count: (COUNT(INCIDENTS!='0') / SUM(DISTINCT(OBSERVATIONS))) * 100 AS FREQUENCY_PERCENT
like: (COUNT(CASE WHEN SUM(INCIDENTS) = '0' THEN '0' ELSE COUNT(INCIDENTS!='0') END) / SUM(DISTINCT(OBSERVATIONS))) * 100 AS FREQUENCY_PERCENT, I get the following error:
SQL compilation error: Aggregate functions cannot be nested: [SUM(CAST("values".INCIDENTS AS FLOAT))] nested in [COUNT(IFF((SUM(CAST("values".INCIDENTS AS FLOAT))) = (CAST('0' AS FLOAT)), TO_NUMBER('0', 18, 0), COUNT(CAST("values".INCIDENTS != '0' AS BOOLEAN))))]
I have seen examples online of nested Aggregate Functions working. Code examples are appreciated.
The first line:
CASE WHEN SUM(INCIDENTS) = '0' THEN '0' ELSE COUNT(INCIDENTS!='0') END
is a conditional aggreation, simplified to COUNT_IF:
COUNT_IF(INCIDENTS != '0') AS INCIDENTS
The second one:
COUNT_IF(INCIDENTS != '0')/NULLIF(SUM(DISTINCT OBSERVATIONS)),0) * 100
AS FREQUENCY_PERCENT
It is always good to secure against division by 0, thus NULLIF(exp, 0).
Related
I have a query that is excluding records where there is no match on the first join. Below is only giving Driver_Trend records that have a match in Driver_Incidents though I need it to include ones that are not found in Driver_Incidents.
SELECT A.DRIVER_NAME AS DRIVER_NAME, A.DRIVER_ID AS DRIVER_ID, C.TRC_TERMINAL AS CSC, A.OBSERVATIONS AS OBSERVATIONS,
A.INCIDENTS AS INCIDENTS, B.SPEED_LIMIT AS SPEED_LIMIT, B.SPEED AS SPEED, B.DIFFERENCE AS DIFFERENCE,
A.REPORT_DATE AS REPORT_DATE, B.TIME AS TIME,
CASE WHEN DIFFERENCE >= 6 AND DIFFERENCE <= 10 THEN '1' ELSE '0' END AS SIX_TEN_MPH,
CASE WHEN DIFFERENCE > 10 AND DIFFERENCE <= 15 THEN '1' ELSE '0' END AS ELEVEN_FIFTEEN_MPH,
CASE WHEN DIFFERENCE > 15 THEN '1' ELSE '0' END AS SIXTEEN_PLUS_MPH
FROM "PROD"."PUBLIC"."SG_DRIVER_TREND" A
LEFT JOIN "PROD"."PUBLIC"."SG_DRIVER_INCIDENTS" B
ON A.DRIVER_ID = B.DRIVER_ID
LEFT JOIN "PROD"."PUBLIC"."TMW_TRACTORPROFILE" C
ON B.Vehicle = C.TRC_NUMBER
WHERE A.DRIVER_ID != ''
AND A.REPORT_DATE BETWEEN '2022-07-01' AND '2022-07-31'
AND B.TIME BETWEEN '2022-07-01' AND '2022-07-31'
AND SUBSTRING(B.TIME, 0, 10) <= A.REPORT_DATE -- Less than or equal to report date
AND SUBSTRING(B.TIME, 0, 10) > SUBSTRING(DATEADD(week,-1, A.REPORT_DATE), 0, 10) -- Greater than 1 week ago
I have tried all different types of joins but still no luck. Could this query be rewritten to get what I need with Subselect or other? Code examples would be appreciated. This is in Snowflake if that matters.
Conditions in WHERE clause referencing outer table makes the query to effectively work as INNER JOIN and should be moved to ON clasue instead:
SELECT A.DRIVER_NAME AS DRIVER_NAME, A.DRIVER_ID AS DRIVER_ID, C.TRC_TERMINAL AS CSC, A.OBSERVATIONS AS OBSERVATIONS,
A.INCIDENTS AS INCIDENTS, B.SPEED_LIMIT AS SPEED_LIMIT, B.SPEED AS SPEED, B.DIFFERENCE AS DIFFERENCE,
A.REPORT_DATE AS REPORT_DATE, B.TIME AS TIME,
CASE WHEN DIFFERENCE >= 6 AND DIFFERENCE <= 10 THEN '1' ELSE '0' END AS SIX_TEN_MPH,
CASE WHEN DIFFERENCE > 10 AND DIFFERENCE <= 15 THEN '1' ELSE '0' END AS ELEVEN_FIFTEEN_MPH,
CASE WHEN DIFFERENCE > 15 THEN '1' ELSE '0' END AS SIXTEEN_PLUS_MPH
FROM "PROD"."PUBLIC"."SG_DRIVER_TREND" A
LEFT JOIN "PROD"."PUBLIC"."SG_DRIVER_INCIDENTS" B
ON A.DRIVER_ID = B.DRIVER_ID
AND B.TIME BETWEEN '2022-07-01' AND '2022-07-31'
AND SUBSTRING(B.TIME, 0, 10) <= A.REPORT_DATE -- Less than or equal to report date
AND SUBSTRING(B.TIME, 0, 10) > SUBSTRING(DATEADD(week,-1, A.REPORT_DATE), 0, 10)
LEFT JOIN "PROD"."PUBLIC"."TMW_TRACTORPROFILE" C
ON B.Vehicle = C.TRC_NUMBER
WHERE A.DRIVER_ID != ''
AND A.REPORT_DATE BETWEEN '2022-07-01' AND '2022-07-31';
I have a query that does not return the expense value if the drvalue(Debtor Value) is equal to 0 or NULL,
If i change the drvalue to any value greater than 0, query returns the expenses value.
Drvalue is a sum of all the values for a specific period
Below is the query
SELECT f.vehiclenumber,f.fleettype,f.IsCreditor,
ISNULL(SUM(l.DrValue),0) AS drvalue,
CASE WHEN iscreditor=1 then Sum (DrValue) - Sum(CrValue) else null end AS Profit,
sum(l.CrValue) AS CrValue ,
sum(l.distance) AS LoadDist,
sum(l.DrValue)/DDist AS DRVal ,
d.Liters AS Liters,d.ddist AS DDist, d.DDiesel AS DDiesel, d.DieselCost AS dieslCost,
(MAX(isnull(l.Closingkm,0))-MIN(isnull(l.OpeningKM,0))) AS [CO],ISNULL(SUM(l.DrValue),0) / CASE WHEN (isnull(MAX(l.Closingkm),0)-MIN(isnull(l.OpeningKM,0)))=0 THEN 1 ELSE (isnull(MAX(l.Closingkm),0)-MIN(isnull(l.OpeningKM,0))) END AS TotalCPK,
(d.DieselCost/sum(l.DrValue)) * 100 AS DieselPerc,
SUM(jobdetails.total) AS Expenses,
count(l.vehicleNo) AS LoadCount
FROM tblVehicle AS f
LEFT JOIN (SELECT Vehicleno, loaddate, DrValue, CrValue,Distance, OpeningKM, closingkm FROM tblloads WHERE DrValue IS NOT NULL) AS l ON f.VehicleNumber = l.VehicleNo AND l.loaddate >= '2020-06-01' and l.loaddate <= '2020-06-30'
LEFT JOIN (SELECT fleet , NULLIF(SUM(Liters),0) AS Liters,NULLIF(sum(distance),0) AS DDist, NULLIF(sum(distance)/ CASE WHEN sum(Liters)=0 THEN 1 ELSE sum(Liters) END,0) AS DDiesel, NULLIF(SUM (Manual_Amount),0) AS DieselCost FROM tblinput
WHERE [Date] >= '2020-06-01' And [Date] <= '2020-06-30'
GROUP BY Fleet) AS d ON l.VehicleNo = d.Fleet
LEFT JOIN (SELECT jd.fleet, SUM(Total) AS total From tblJobDetails jd, tbljobcards WHERE tbljobcards.JobID = jd.jobid AND jobdate >= '2020-06-01' AND jobdate <= '2020-06-30' GROUP BY jd.fleet) AS jobdetails ON jobdetails.fleet = l.vehicleno
WHERE VehicleCategory <> 'T'
GROUP BY f.vehiclenumber,f.fleettype,f.IsCreditor,d.Liters,d.ddist, d.DDiesel,d.DieselCost
ORDER BY fleettype
RESULTS
I want to show top ten customers,sales,margin where customers is registred during this accounting year. The query takes about 65seconds to run and it is not accepted :-(
As you may see i am not good at sql and will be very happy for help to improve the query.
SELECT Top 10
AcTr.R3, Actor.Nm,
SUM(CASE WHEN AcTr.AcNo<='3999' THEN AcAm*-1 ELSE 0 END) AS Sales ,
SUM(AcAm*-1) AS TB
FROM AcTr, Actor
WHERE (Actor.CustNo = AcTr.R3) AND
(Actor.CustNo <> '0') AND
(Actor.CreDt >= '20180901') AND
(Actor.CreDt <= '20190430') AND
AcTr.AcYr = '2018' AND
AcTr.AcPr <= '8' AND
AcTr.AcNo>='3000' AND
AcTr.AcNo <= '4999'
GROUP BY AcTr.R3, Actor.Nm
ORDER BY Sales DESC
Welcome to the community. You have a good start, but future, it is more helpful if you can provide (as commented), the CREATE table declarations so users know the actual data types. Not always required, but helps.
As for your query layout, it is more common to show the JOIN syntax instead of WHERE showing relations between tables, but that comes in time and practice.
Indexes help and should be based on a combination of both WHERE/JOIN criteria AND Grouping fields. Also, if fields are numeric, then do not 'quote' them, just leave as numbers. For example, your AcYr, AcPr, AcNo. I would think that an account number really would be a string value vs number for accounting purposes.
I would suggest the following indexes on your tables
Table Index
Actr ( AcYr, AcPr, AcNo, R3 )
Actor ( CustNo, CreDt )
The Actr table I have the filtering criteria first and the R3 last to help optimize the GROUP BY. The Actor table by the customer number, then the CreDt (Create date??), and is it really a string, or is it a date field? If so, the date criteria would be something like '2018-09-01' and '2019-04-30'
select TOP 10
Actor.Nm,
PreSum.Sales,
PreSm.TB
from
( select
R3,
SUM(CASE WHEN AcTr.AcNo <= '3999'
THEN AcAm * -1 ELSE 0 END) AS Sales,
SUM( AcAm * -1) AS TB
from
Actr
where
AcTr.AcYr = 2018
AND AcTr.AcPr <= 8
AND AcTr.AcNo >= '3000'
AND AcTr.AcNo <= '4999'
GROUP BY
AcTr.R3 ) PreSum
JOIN Actor
on PreSum.R3 = Actor.CustNo
AND Actor.CustNo <> 0
AND Actor.CreDt >= '20180901'
AND Actor.CreDt <= '20190430'
order by
Sales DESC
Per latest inquiry / comment, wanting by year comparison and getting rid of the top 10 performers per a given time period.
select
Actor.Nm,
PreSum.Sales2018,
PreSum.Sales2019,
PreSum.TB2018,
PreSum.TB2019
from
( select
AcTr.R3,
SUM(CASE WHEN AcTr.AcYr = 2018
AND AcTr.AcNo <= '3999'
THEN AcAm * -1 ELSE 0 END) AS Sales2018,
SUM(CASE WHEN AcTr.AcYr = 2019 AND AcTr.AcNo <= '3999'
THEN AcAm * -1 ELSE 0 END) AS Sales2019,
SUM( CASE WHEN AcTr.AcYr = 2018
THEN AcAm * -1 else 0 end ) AS TB2018
SUM( CASE WHEN AcTr.AcYr = 2019
THEN AcAm * -1 else 0 end ) AS TB2019
from
Actr
where
AcTr.AcYr IN ( 2018, 2019 )
AND AcTr.AcPr <= 8
AND AcTr.AcNo >= '3000'
AND AcTr.AcNo <= '4999'
GROUP BY
AcTr.R3 ) PreSum
JOIN Actor
on PreSum.R3 = Actor.CustNo
AND Actor.CustNo <> 0
AND Actor.CreDt >= '20180901'
AND Actor.CreDt <= '20190430'
order by
Sales DESC
I am trying to work on a query to fill the Price for a product where it is zero with non-zero value fro previous record. I tried to write a simple correlated subquery but its not working.
var_1 = select * from "XYZ"."PRD_TEST" where price <> 0 order by period desc;
var_out = select a.product,a.period, ( select price from :var_1 b where a.product = b.product and a.period > b.period and b.period <> 0 limit 1 ) as price from "XYZ"."PRD_TEST" a;
PRODUCT PERIOD PRICE
A 1 100
A 2 0 - to be filled with 100
A 3 0 - to be filled with 100
A 4 5
A 5 0 - to be filled with 5
I tried to replace the sub-query with scalar function but it does not take table as a Parameter.
I tried to achieve the output using Left outer join and Row_number but it's too expensive and runs for a long time.
I am looking for a best option to fetch only 1 record in the subquery just like TOP 1.
you could use a scalar subquery like this ( select ... limit 1 is not considered scalar in HANA, unfortunately):
Do begin
var_1 = select * from (( Select 'A' product, '1' period, '100' price from sys.dummy )
Union ( Select 'A' product, '2' period, '0' price from sys.dummy )
Union ( Select 'A' product, '3' period, '0' price from sys.dummy )
Union ( Select 'A' product, '4' period, '5' price from sys.dummy )
Union ( Select 'A' product, '5' period, '0' price from sys.dummy )) order by period desc;
var_out = ( select a.product,
a.period,
( select max(price)
from :var_1 b
where a.product = b.product
and a.period > b.period
and b.period <> 0
and b.period = ( select max(period) from :var_1 c
where a.product = c.product
AND a.period > c.period
and c.period <> 0
and c.price <> 0
)) as price
from :var_1 a where price = '0' )
union (select product, period, price from :var_1 where price <> '0' );
select * from :var_out order by product, period;
end
Tested on sps12
Added after comment.
Why don't you just try? It is very simple.
Because I was curious I tried it on my HCP trial instance, takes about 1 sec for on milion rows. I included a ifnull to avoid rows with null-values where there is no price in earlier periods.
Here is the coding:
drop table var_1;
create column table var_1 as
(
select
cast ( 'Prod' || prd.GENERATED_PERIOD_START as nvarchar(20) ) product,
cast ( per.GENERATED_PERIOD_START as decimal(2)) period,
cast ( case when rand() < '0.5' then rand() * '100' else '0' end
as decimal(5,2)) as price -- ~50% of price is 0
from series_generate_integer(1,0,1000000/13) as prd, --~1Mio records
series_generate_integer(1,0,13) as per --12 periods + period 0
);
merge delta of var_1;
select * from var_1
order by product, period
limit 100;
do begin sequential execution -- don't let parallel execution influence the runtime-measurement
declare start_timestamp timestamp;
start_timestamp = current_timestamp;
var_out = ( select a.product,
a.period,
ifnull ((select max(price)
from var_1 b
where a.product = b.product
and a.period > b.period
and b.period <> 0
and b.period = ( select max(period) from var_1 c
where a.product = c.product
AND a.period > c.period
and c.period <> 0
and c.price <> 0
)),'0.0') as price
from var_1 a where price = '0' )
union (select product, period, price from var_1 where price <> '0' );
select nano100_between(:start_timestamp, (select current_timestamp from dummy) )/10000 as runtime_millisec from dummy;
select * from :var_out
order by product, period
limit 100;
end
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
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.
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) */
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.