Reputation: 37
I'm trying to fill missing months in a SELECT query. It looks like this :
SELECT sl.loonperiode_dt, (sum(slr.uren)) code_220
FROM HR.soc_loonbrief_regels slr,
HR.soc_loonbrieven sl,
HR.werknemers w,
HR.v_kontrakten vk
WHERE sl.loonperiode_dt BETWEEN '01012018' AND '01122018'
AND slr.loon_code_id IN (394)
AND slr.loonbrief_id = sl.loonbrief_id
AND w.werknemer_id = sl.werknemer_id
AND w.werknemer_id = vk.werknemer_id
AND vk.functie_id IN (121, 122, 128)
AND sl.loonperiode_dt BETWEEN hist_start_dt AND last_day(nvl(hist_eind_dt, sl.loonperiode_dt))
AND w.afdeling_id like '961'
GROUP BY sl.loonperiode_dt
ORDER BY sl.loonperiode_dt
It outputs this table :
31/01/18 234
30/04/18 245,8
31/05/18 714,6
31/07/18 288,04
31/08/18 281
30/11/18 515,12
I obviously would like it to be like that :
31/01/18 234
28/02/18 0
31/03/18 0
30/04/18 245,8
31/05/18 714,6
30/06/18 0
31/07/18 288,04
31/08/18 281
30/09/18 0
31/10/18 0
30/11/18 515,12
31/12/18 0
I have a calendar table 'CONV_HC.calendar' with dates in a column named 'DAT'. I have seen many questions and answers about this, but I can't figure out how to apply the LEFT JOIN method or any other one to my current problem.
Thanks a lot in advance,
Upvotes: 0
Views: 1118
Reputation: 1009
You could have a already done table with months and "join" with it, group by the date, or you can create one with subquery or using a with statement, something like
WITH Months (month) AS (
SELECT 1 AS Month FROM DUAL
UNION ALL
SELECT MONTH + 1
FROM Months
WHERE MONTH < 12
)
SELECT *
FROM Months
LEFT JOIN SomeTable
ON SomeTable.month = Months.MONTH
--ON Extract(MONTH FROM SomeTable.date) = Months.MONTH
edit
A better example:
--Just to simulate some table data
WITH SomeData AS (
SELECT TO_DATE('01/01/2019', 'MM/DD/YYYY') AS Dat, 5 AS Value FROM dual
UNION ALL
SELECT TO_DATE('01/05/2019', 'MM/DD/YYYY') AS Dat, 7 AS Value FROM dual
UNION ALL
SELECT TO_DATE('03/03/2019', 'MM/DD/YYYY') AS Dat, 2 AS Value FROM dual
UNION ALL
SELECT TO_DATE('11/05/2019', 'MM/DD/YYYY') AS Dat, 9 AS Value FROM dual
)
, Months (StartDate, MaxYear) AS (
SELECT CAST(TO_DATE('01/01/2019', 'MM/DD/YYYY') AS DATE) AS StartDate, 2019 AS MaxYear FROM DUAL
UNION ALL
SELECT CAST(ADD_MONTHS(StartDate, 1) AS DATE), MaxYear
FROM Months
WHERE EXTRACT(YEAR FROM ADD_MONTHS(StartDate, 1)) <= MaxYear
)
SELECT
Months.StartDate AS Dat
, SUM(SomeData.Value) AS SumValue
FROM Months
LEFT JOIN SomeData
ON Extract(MONTH FROM SomeData.Dat) = Extract(MONTH FROM Months.StartDate)
GROUP BY
Months.StartDate
edit
You won't find a just copy past solution, you need to get the idea from it and change to your context.
let's try this. You can "add" the missing months in an APP, or you can JOIN it with a already done table, doesn't need to be a real table, you can make one. The with statement is an example of it. So lets get all month, at the last day for 2019:
--Geting the last day of every month for 2019
WITH Months (CurrentMonth, MaxYear) AS (
SELECT CAST(TO_DATE('01/01/2019', 'MM/DD/YYYY') AS DATE) AS CurrentMonth, 2019 AS MaxYear FROM DUAL
UNION ALL
SELECT CAST(ADD_MONTHS(CurrentMonth, 1) AS DATE), MaxYear
FROM Months
WHERE EXTRACT(YEAR FROM ADD_MONTHS(CurrentMonth, 1)) <= MaxYear
)
SELECT LAST_DAY(Months.CurrentMonth) AS LastDay
FROM Months
Ok, now we have all months avaliable for the join. In your query, you already have the sum done so lets skip the sum and just use your data. Just add another with query.
--Geting the last day of every month for 2018
WITH Months (CurrentMonth, MaxYear) AS (
SELECT CAST(TO_DATE('01/01/2018', 'MM/DD/YYYY') AS DATE) AS CurrentMonth, 2018 AS MaxYear FROM DUAL
UNION ALL
SELECT CAST(ADD_MONTHS(CurrentMonth, 1) AS DATE), MaxYear
FROM Months
WHERE EXTRACT(YEAR FROM ADD_MONTHS(CurrentMonth, 1)) <= MaxYear
)
, YourData as (
SELECT sl.loonperiode_dt, (sum(slr.uren)) code_220
FROM HR.soc_loonbrief_regels slr,
HR.soc_loonbrieven sl,
HR.werknemers w,
HR.v_kontrakten vk
WHERE sl.loonperiode_dt BETWEEN '01012018' AND '01122018'
AND slr.loon_code_id IN (394)
AND slr.loonbrief_id = sl.loonbrief_id
AND w.werknemer_id = sl.werknemer_id
AND w.werknemer_id = vk.werknemer_id
AND vk.functie_id IN (121, 122, 128)
AND sl.loonperiode_dt BETWEEN hist_start_dt AND last_day(nvl(hist_eind_dt, sl.loonperiode_dt))
AND w.afdeling_id like '961'
GROUP BY sl.loonperiode_dt
--ORDER BY sl.loonperiode_dt
)
SELECT
LAST_DAY(Months.CurrentMonth) AS LastDay
, COALESCE(YourData.code_220, 0) AS code_220
FROM Months
Left Join YourData
on Extract(MONTH FROM Months.CurrentMonth) = Extract(MONTH FROM YourData.loonperiode_dt)
--If you have more years: AND Extract(YEAR FROM Months.CurrentMonth) = Extract(YEAR FROM YourData.loonperiode_dt)
ORDER BY LastDay ASC
Upvotes: 1