生成包含空月份的月份数据系列?
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()
的参数以适应不同的会计年度。
我返回了一个简单的日历年月度数据集,但我知道我会缺少月份(即没有数据)。
我在这里找到了这个答案:
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()
的参数以适应不同的会计年度。