这里一个有用的技术是创建一个包含“所有”日期的表(显然这将是无限的,所以我的意思是为您的目的提供足够大的范围)或创建两个表:所有月份之一(12 行)和另一个“所有”年份。
假设您选择其中的第一个:
create table all_dates (d date)
并根据需要进行填充。我将按如下方式定义您的事件表
create table incident
(
incident_id int not null,
project_id int not null,
start_date date not null,
end_date date null
)
我不确定您使用的是什么 RDBMS,并且日期函数在它们之间有很大差异,因此下一点可能需要根据您的需要进行调整。
select
project_id,
datepart(yy, all_dates.d) as "year",
datepart(mm, all_dates.d) as "month",
count(*) as "count"
from
incident,
all_dates
where
incident.start_date <= all_dates.d and
(incident.end_date >= all_dates.d or incident.end_date is null)
group by
project_id,
datepart(yy, all_dates.d) year,
datepart(mm, all_dates.d) month
这不会像我们希望的那样工作,因为每个月发生事件的每一天都会统计。要解决这个问题,我们需要使用子查询或临时表,这实际上取决于 RDBMS...
它的另一个问题是,对于未解决的事件,它会在你的 all_dates 表中显示它们与未来的所有月份。添加all_dates.d <= today 解决了这个问题。同样,不同的 RDBMS 有不同的方法来回馈现在/今天/系统时间...
另一种方法是使用 all_months 而不是 all_dates 表,其中仅包含月初的日期:
create table all_months (first_of_month date)
select
project_id,
datepart(yy, all_months.first_of_month) as "year",
datepart(mm, all_months.first_of_month) as "month",
count(*) as "count"
from
incident,
all_months
where
incident.start_date <= dateadd(day, -1, dateadd(month, 1, first_of_month)
(incident.end_date >= first_of_month or incident.end_date is null)
group by
project_id,
datepart(yy, all_months.first_of_month),
datepart(mm, all_months.first_of_month)