Sei sulla strada giusta, basta LEFT JOIN
il risultato della tua query in una tabella di nomi di mesi. Quindi i nomi che esistono nel tuo risultato restituiranno una corrispondenza e un NULL
sarà restituito per quei mesi che non sono nel tuo risultato. Un COALESCE
o NVL
o CASE
costrutto, qualunque cosa tu voglia, può essere usata per trasformare quel NULL
in un 0
diretto .
Non è necessario creare una vera tabella di mesi, è possibile ottenere utilizzando una vista in linea, semplicemente una query che genera tutti i dati del mese.
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
Per quanto riguarda la restituzione di tutto per un anno particolare, guarda la condizione WHERE. Suppongo che appt_date_time sia un datetime o un timestamp. Non vuoi scrivere YEAR(appt_date_time) =2012 perché ciò rovinerà le possibilità di utilizzare un indice su quella colonna (suppongo che quella colonna appaia come prima colonna in un indice). Usando un BETWEEN... AND e confrontandolo con datetime letterali, puoi avere una query abbastanza efficiente che soddisfa il requisito.
Inoltre, se GROUP BY
il month(appt_date_time)
mysql assicurerà che anche i risultati vengano ordinati in ordine crescente per mese. Quindi non c'è bisogno di un ORDER BY
separato . Anche l'ordine delle 'gambe' della query UNION verrà mantenuto da mysql.