SELECT TO_CHAR(months.month, 'YYYY-MM') AS month,
COALESCE(SUM(dm.revenue)::FLOAT, 0.0) AS total_amount,
COALESCE(COUNT(dm.id), 0) AS value,
array_agg(dm.id) AS lost_deal_ids
FROM (
SELECT generate_series(DATE_TRUNC('month', CURRENT_DATE) - INTERVAL '4 months', DATE_TRUNC('month', CURRENT_DATE), INTERVAL '1 month')::DATE AS month
) months
LEFT JOIN deal_management dm ON TO_CHAR(dm.closing_date, 'YYYY-MM') = TO_CHAR(months.month, 'YYYY-MM') AND dm.employee_id = 'sojdosdj2920320323'
LEFT JOIN lookup_data ld ON ld.id = dm.pipeline_id
WHERE (TO_CHAR(months.month, 'YYYY-MM') BETWEEN TO_CHAR(CURRENT_DATE - INTERVAL '4 months', 'YYYY-MM') AND TO_CHAR(CURRENT_DATE, 'YYYY-MM')
OR TO_CHAR(months.month, 'YYYY-MM') = TO_CHAR(CURRENT_DATE, 'YYYY-MM'))
AND (ld.level_data = 'Lost' OR ld.id IS NULL)
AND dm.is_evaluate IS NOT TRUE
GROUP BY TO_CHAR(months.month, 'YYYY-MM')
ORDER BY TO_CHAR(months.month, 'YYYY-MM');
I want to see current month's data as
2024-01 | 0 | {null}
But if missing want to see '0'.
Pretty much every aspect of your query needs attention. This might work, and a lot faster, too:
If you want to see '0' instead of null, you can't use an array type for the output column
lost_deal_ids. Usestring_agg()instead ofarray_agg(). (Why bother, though? You count is clear anyway.)The table-function
generate_series()can stand on its own in theFROMlist after we remove the unhelpful cast todate.Use
LOCALTIMESTAMPinstead ofCURRENT_DATE. This way,date_trunc()producestimestampinstead oftimestamptz. See:To put it bluntly, none of your
WHEREconditions make sense.This is 100 % redundant. Twice redundant actually. The 1st boolean expressions is always true, the 2nd is implied by the first:
This is an awkward, inferior way of adding
ld.level_data = 'Lost'as join condition to theLEFT JOIN:This would contradict the
LEFT JOIN. (I resolved by moving it into the join condition):count()never returnsnull. Socoalesce(count( ...never does anything useful.Understand the different role of conditions in
WHEREvs.LEFT JOIN:Your join condition
ON to_char(dm.closing_date, 'YYYY-MM') = to_char(months.month, 'YYYY-MM')was needlessly expensive. And not saragable.Use the sargable expression
ON dm.closing_date >= m.mon AND dm.closing_date < m.mon + interval '1 mon'instead.Use the timestamp value, not the text generated with
to_char()inGROUP BYandORDER BY. Cheaper, and less error prone.Don't use a non-descriptive column alias like "value".
Consider hiring a consultant.