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');
我想查看 2024 年 1 月的当月数据 | 0 | {null} 但如果缺失想看到 0
几乎查询的每个方面都需要关注。这可能有效,而且速度更快:
SELECT to_char(m.mon, 'YYYY-MM') AS month
, coalesce(sum(dm.revenue)::float, 0.0) AS total_amount
, count(dm.id) AS count_deals
, coalesce(string_agg(dm.id::text, ', '), '0') AS lost_deal_ids
FROM generate_series(date_trunc('month', LOCALTIMESTAMP) - interval '4 mon'
, date_trunc('month', LOCALTIMESTAMP)
, interval '1 month') m(mon)
LEFT JOIN deal_management dm ON dm.closing_date >= m.mon
AND dm.closing_date < m.mon + interval '1 mon'
AND dm.employee_id = 'sojdosdj2920320323'
AND dm.is_evaluate IS NOT TRUE
LEFT JOIN lookup_data ld ON ld.id = dm.pipeline_id
AND ld.level_data = 'Lost'
GROUP BY m.mon
ORDER BY m.mon;
在我们删除对
generate_series()
的无用强制转换后,表函数 FROM
可以在 date
列表中独立存在。
使用
LOCALTIMESTAMP
而不是 CURRENT_DATE
。这样,date_trunc()
会生成 timestamp
而不是 timestamptz
。参见:
说白了,你的
WHERE
条件都没有任何意义。
这是 100% 多余的。实际上是多余的两次。第一个布尔表达式始终为 true,第二个布尔表达式由第一个布尔表达式暗示:
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'))
这是一种将
ld.level_data = 'Lost'
作为连接条件添加到 LEFT JOIN
的笨拙、劣质的方法:
WHERE (ld.level_data = 'Lost' OR ld.id IS NULL)
这与
LEFT JOIN
相矛盾。 (我通过将其移至连接条件来解决):
WHERE dm.is_evaluate IS NOT TRUE
count()
永远不会回来null
。所以 coalesce(count( ...
永远不会做任何有用的事情。
您的加入条件
ON to_char(dm.closing_date, 'YYYY-MM') = to_char(months.month, 'YYYY-MM')
不必要地昂贵。而且不是saragable。
请改用可优化控制表达式
ON dm.closing_date >= m.mon AND dm.closing_date < m.mon + interval '1 mon'
。
使用时间戳值,而不是使用
to_char()
和 GROUP BY
中的 ORDER BY
生成的文本。更便宜,而且不易出错。
不要使用非描述性的列别名,例如“value”。
考虑聘请顾问。