SQL - 计算日期率内的活动项目数

SQL - Count number of itemactive within a date rate

我有一个 ResourcesProjectsStartDateEndDate 的数据集。 每个资源都可以被多个项目使用。

我想统计每个季度使用资源的项目数。

因此,如果项目在特定年份的第一季度开始并在当年的第三季度结束,而项目 2 在第二季度开始并在第三季度结束,我想计算第二季度的 2 个项目,因为在第一季度期间,项目 1 和项目 2 处于活动状态。

这是我的数据集:

create table Projects
(Resource_Name varchar(20)
,Project_Name varchar(20)
,StartDate varchar(20)
,EndDate varchar(20)
)


insert into Projects values('Resource 1','Project A','15/01/2013','1/11/2014')
insert into Projects values('Resource 1','Project B','1/03/2013','1/09/2016')
insert into Projects values('Resource 1','Project C','1/04/2013','1/09/2015')
insert into Projects values('Resource 1','Project D','1/06/2013','1/03/2016')
insert into Projects values('Resource 1','Project E','15/01/2013','1/09/2015')
insert into Projects values('Resource 1','Project F','3/06/2013','1/11/2015')

这是我正在寻找的结果:

Resource Name| Year | Quarter|Active Projects
Resource 1     2013     1           2
Resource 1     2013     2           6

您可以通过确定项目处于活动状态的第一个和最后一个季度,然后使用累计和来完成此操作。在 SQL Server 2012+ 中,这看起来像

select resource_name, yyyyq, 
       (sum(sum(s)) over (partition by resource_name order by yyyyq) -
        sum(sum(e)) over (partition by resource_name order by yyyyq) +
        e
       ) as activeProjects
from ((select resource_name, datepart(year, startdate) + datepart(quarter, startdate) as yyyyq, 1 as s, 0 as e
       from projects
      ) union all
      (select resource_name, datepart(year, enddate) + datepart(quarter, enddate), 0 as s, 1 as e
       from projects
      )
     ) yq
group by resource_name, yyyyq;

在早期版本中,您可以使用 cross apply 执行类似的操作。

使用计数 table:

使用 Projects 中的日期生成所有季度及其开始日期和结束日期的列表,在本例中为 CteQuarter(sd, ed)。之后,您只需要 JOIN Projects table 到 CteQuarter 重叠日期。最后,GROUP BY 使用日期的 YEARQuarter 部分。

SQL Fiddle

WITH CteYear(yr) AS(
    SELECT number
    FROM master..spt_values
    WHERE 
        type = 'P'
        AND number >= (SELECT MIN(YEAR(CONVERT(DATE, StartDate, 103))) FROM Projects)
        AND number <= (SELECT MAX(YEAR(CONVERT(DATE, EndDate, 103))) FROM Projects)
),
CteQuarter(sd, ed) AS(
    SELECT
        DATEADD(QUARTER, q.n - 1, DATEADD(YEAR, cy.yr - 1900, 0)),
        DATEADD(DAY, -1, DATEADD(QUARTER, q.n, DATEADD(YEAR, cy.yr - 1900, 0)))
    FROM CteYear AS cy
    CROSS JOIN(
        SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4
    ) AS q(n)
)
SELECT 
    p.Resource_Name,
    [Year] = DATEPART(YEAR, q.sd),
    [Quarter] = DATEPART(QUARTER, q.sd),
    [Active Projects] = COUNT(*)
FROM Projects p
INNER JOIN CteQuarter q
    ON CONVERT(DATE, StartDate, 103) <= q.ed
    AND CONVERT(DATE, EndDate, 103) >= q.sd
GROUP BY 
    p.Resource_Name,
    DATEPART(YEAR, q.sd),
    DATEPART(QUARTER, q.sd)
ORDER BY
    p.Resource_Name,
    DATEPART(YEAR, q.sd),
    DATEPART(QUARTER, q.sd)

备注:

  1. Here 是检查重叠日期的好方法。
  2. Some common date routines

结果:

| Resource_Name | Year | Quarter | Active Projects |
|---------------|------|---------|-----------------|
|    Resource 1 | 2013 |       1 |               3 |
|    Resource 1 | 2013 |       2 |               6 |
|    Resource 1 | 2013 |       3 |               6 |
|    Resource 1 | 2013 |       4 |               6 |
|    Resource 1 | 2014 |       1 |               6 |
|    Resource 1 | 2014 |       2 |               6 |
|    Resource 1 | 2014 |       3 |               6 |
|    Resource 1 | 2014 |       4 |               6 |
|    Resource 1 | 2015 |       1 |               5 |
|    Resource 1 | 2015 |       2 |               5 |
|    Resource 1 | 2015 |       3 |               5 |
|    Resource 1 | 2015 |       4 |               3 |
|    Resource 1 | 2016 |       1 |               2 |
|    Resource 1 | 2016 |       2 |               1 |
|    Resource 1 | 2016 |       3 |               1 |