【问题标题】:SQL - Count number of itemactive within a date rateSQL - 在日期速率内计算 itemactive 的数量
【发布时间】:2015-12-04 20:51:51
【问题描述】:

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

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

因此,如果项目在特定年份的 Q1 开始并在该年的 Q3 结束,并且 project2 在 Q2 开始并在 Q3 结束,我想计算 Q2 的 2 个项目,因为在 Q1 期间 project1 和 project2 都是活跃。

这是我的数据集:

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 sql-server tsql date-range


    【解决方案1】:

    您可以通过确定项目处于活动状态的第一季度和最后一个季度,然后使用累积总和来做到这一点。在 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 执行类似的操作。

    【讨论】:

      【解决方案2】:

      使用计数表:

      使用Projects 中的日期,生成所有季度及其开始日期和结束日期的列表,在本例中为CteQuarter(sd, ed)。之后,您只需将JOIN Projects 表发送到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 |
      

      【讨论】:

      • 问:DATEADD(YEAR, cy.yr - 1900, 0) 是做什么的?
      • 获取一年中的第一天cy.yr
      • 好的,但为什么需要 1900?
      • 因为日期0的意思是1900-01-01
      • 我知道他做了什么。还不确定如何。首先有一个years 的列表来覆盖数据。然后将所有这些年份拆分为 quarters 的开始日期和结束日期。检查每个quarter 并查看有多少项目在quarter 上有一些部分
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-22
      • 1970-01-01
      • 1970-01-01
      • 2021-02-03
      相关资源
      最近更新 更多