Você precisa gerar todas as datas desejadas e, em seguida, juntar seus dados às datas. Observe também que é importante colocar alguns predicados no
ON
da junção esquerda cláusula e outros no WHERE
cláusula:SELECT
CONCAT(y, '-', LPAD(m, 2, '0')) as byMonth,
COUNT(`created`) AS Total
FROM (
SELECT year(now()) AS y UNION ALL
SELECT year(now()) - 1 AS y
) `years`
CROSS JOIN (
SELECT 1 AS m UNION ALL
SELECT 2 AS m UNION ALL
SELECT 3 AS m UNION ALL
SELECT 4 AS m UNION ALL
SELECT 5 AS m UNION ALL
SELECT 6 AS m UNION ALL
SELECT 7 AS m UNION ALL
SELECT 8 AS m UNION ALL
SELECT 9 AS m UNION ALL
SELECT 10 AS m UNION ALL
SELECT 11 AS m UNION ALL
SELECT 12 AS m
) `months`
LEFT JOIN `qualitaet` q
ON YEAR(`created`) = y
AND MONTH(`created`) = m
AND `status` = 1
WHERE STR_TO_DATE(CONCAT(y, '-', m, '-01'), '%Y-%m-%d')
>= MAKEDATE(year(now()-interval 1 year),1) + interval 5 month
AND STR_TO_DATE(CONCAT(y, '-', m, '-01'), '%Y-%m-%d')
<= now()
GROUP BY y, m
ORDER BY y, m
Como funciona o acima?
CROSS JOIN
cria um produto cartesiano entre todos os anos disponíveis e todos os meses disponíveis. Isso é o que você quer, você quer todas as combinações ano-mês sem lacunas.LEFT JOIN
adiciona todos osqualitaet
registros ao resultado (se existirem) e os une ao produto cartesiano ano-mês anterior. É importante colocar predicados como ostatus = 1
predicado aqui.COUNT(created)
conta apenas valores não NULL decreated
, ou seja, quando oLEFT JOIN
não produz linhas para nenhum ano-mês, queremos0
como resultado, não1
, ou seja, não queremos contar oNULL
valor.
Uma observação sobre o desempenho
O acima faz uso pesado de operações de string e aritmética de data e hora em seu
ON
e WHERE
predicados. Isso não vai funcionar para muitos dados. Nesse caso, você deve pré-truncar e indexar melhor seus anos-meses no qualitaet
tabela, e operar apenas nesses valores.