生成包含空月份的月份数据系列?

Generate month data series with null months included?

我返回了一个简单的日历年月度数据集,但我知道我会缺少月份(即没有数据)。

我在这里找到了这个答案:

Best way to count records by arbitrary time intervals in Rails+Postgres

很接近,但我不明白 JOIN USING 语法。

大部分时间我都想好了:

SELECT TO_CHAR(activity_tasks.start_date, 'MON') AS month,
EXTRACT(MONTH FROM activity_tasks.start_date) AS month_num,
SUM(cost_planned) FILTER (WHERE activity_tasks.aasm_state IN ('open', 'planned' ) )  AS planned,
SUM(cost_actual) FILTER (WHERE activity_tasks.aasm_state IN ('closed' ) ) AS actual
FROM "activity_tasks"
WHERE activity_tasks.start_date >= '2020-01-01' AND activity_tasks.start_date <= '2020-12-31'
GROUP BY month, month_num
ORDER BY month_num

这让我:

+-------+-----------+---------+--------+
| month | month_num | planned | actual |
+-------+-----------+---------+--------+
| NOV   | 11        | NULL    | 123    |
| DEC   | 12        | 500     | NULL   |
+-------+-----------+---------+--------+

我只想加入:

SELECT *
FROM  (
   SELECT to_char(m, 'MON') AS mmm
   FROM generate_series('2020-01-01', '2020-12-31', interval '1 month') m
) m

输入一个简单的表达式,得到一个完整的 JAN-DEC 数据集,包括空月份。

附加问题: 是否有更优雅的 SQL 来构建 generate_series('2020-01-01', '2020-12-31', interval '1 month') 月份数组并设置我的 WHERE activity_tasks.start_date >= '2020-01-01' AND activity_tasks.start_date <= '2020-12-31'?在我的例子中,默认值是给定年份的 1 月 1 日,但可能存在会计会计年度是其他月份的情况,并希望避免此处出现重复逻辑,并且可能只输入一个开始日期。

您可以使用 generate_series() 生成所有月份的开始,然后将 table 与 left join 一起使用:

select 
    to_char(d.start_date, 'mon') as month,
    extract(month from d.start_date) as month_num,
    sum(cost_planned) filter (where t.aasm_state in ('open', 'planned' ) )  as planned,
    sum(cost_actual)  filter (where t.aasm_state = 'closed') as actual
from generate_series('2020-01-01'::date, '2020-12-01'::date, '1 month') d(start_date)
left join activity_tasks t
    on t.start_date >= d.start_date and t.start_date < d.start_date + '1 month'::interval
group by start_date
order by start_date

您可以轻松更改 generate_series() 的参数以适应不同的会计年度。