Je bent op de goede weg, gewoon LEFT JOIN
het resultaat van uw zoekopdracht naar een tabel met maandnamen. Dan zullen de namen die in uw resultaat voorkomen een overeenkomst opleveren, en een NULL
worden geretourneerd voor de maanden die niet in uw resultaat staan. Een COALESCE
of NVL
of CASE
constructie, wat je maar wilt, kan worden gebruikt om die NULL
. te veranderen in een rechte 0
.
U hoeft geen echte maandtabel te maken, u kunt deze krijgen door een inline weergave te gebruiken - gewoon een zoekopdracht die alle maandgegevens genereert.
select months.month, coalesce(appts.monthly_total, 0) monthly_total
from (
select 'January' as month
union all select 'February'
union all select 'March'
...etc...
union all select 'December'
) months
left join (
select sum(service_price) as monthly_total,
monthname(appt_date_time) as month
from appt_tbl
inner join services_tbl
on appt_tbl.service_id = services_tbl.service_id
where appt_date_time between '2012-01-01 00:00:00'
and '2012-12-31 23:59:59'
group by month(appt_date_time)
) appts
on months.month = appts.month
Wat betreft het retourneren van alles voor een bepaald jaar, kijk naar de WAAR-voorwaarde. Ik neem aan dat appt_date_time een datetime of tijdstempel is. Je wilt YEAR(appt_date_time) =2012 niet schrijven, omdat dat de kans verpest om een index in die kolom te gebruiken (ik neem aan dat die kolom als eerste kolom in een index verschijnt). Door een BETWEEN...AND te gebruiken en te vergelijken met letterlijke datetimes, kunt u een behoorlijk efficiënte query hebben die aan de vereiste voldoet.
Ook als u GROUP BY
op month(appt_date_time)
mysql zorgt ervoor dat de resultaten ook oplopend per maand worden gesorteerd. Dus geen aparte ORDER BY
nodig . De volgorde van de 'benen' van de UNION-query wordt ook bewaard door mysql.