SQL 重叠日期范围

Posted

技术标签:

【中文标题】SQL 重叠日期范围【英文标题】:SQL Overlapping Date Range 【发布时间】:2013-07-17 19:24:32 【问题描述】:

我有一个包含 3 个字段“开始日期”和“结束日期”以及“分配百分比”的表格。我将需要找出该表中从当前日期起 3 个月内的所有记录,

而且(这个很棘手)只有 Sum(Allocation %) > 100 的日期范围重叠的记录。

请帮我提出一个问题。

这是表架构。

Table (ResourceAssignment)
   - ResourceAssignmentID (PK)
   - ResourceID (FK)
   - Assigned To (FK)
   - Start Date
   - End Date
   - Allocation %

我基本上需要在一定时期内(从当天到3个月)找到全部分配的资源。

提前致谢!

【问题讨论】:

重叠的日期范围是什么意思?您是指开始或结束日期在当前日期后 3 个月内的任何记录吗? 请将您的架构添加到sqlfiddle.com、一些示例数据和所需输出的示例,以便我们更好地为您提供帮助。 【参考方案1】:

不确定这是否是您所追求的,但这会向您显示分配高于 100% 的所有 ResourceID,其开始或结束日期在过去 3 个月内:

SELECT ResourceID 
FROM ResourceAssignment
WHERE StartDate BETWEEN DATEADD(month,-3,GETDATE())  AND GETDATE()
  OR EndDate BETWEEN DATEADD(month,-3,GETDATE())  AND GETDATE()
GROUP BY ResourceID 
HAVING SUM([Allocation %]) > 100

【讨论】:

好点,不清楚哪个领域属于那里,但显然不是PK。 如果结果中需要包含“open assignments”,将WHERE子句的第二部分修改如下:OR ( (EndDate IS NULL) OR (EndDate BETWEEN DATEADD(month,-3,GETDATE()) AND GETDATE())) 如果您在 1 月 1 日至 1 月 15 日分配了 80% 的资源,并且在 1 月 16 日至 1 月 31 日分配了 85% 的资源,则此查询将说它在 165% 时过度分配。这并不能回答过度分配 重叠 范围的问题。 是的,我要求澄清 OP 所说的重叠是什么意思,因为问题不清楚。【参考方案2】:

您有两种通用解决方案。哪个最好取决于 ResourceAllocation 的大小、冲突的频率以及您打算如何呈现数据。

解决方案 1:列出未来 3 个月内的日期并与之对照,以确定哪些日期被过度分配

WITH
  datelist AS (
    SELECT CAST(GETDATE() AS date) [d] UNION ALL SELECT DATEADD(day,1,[d]) FROM datelist WHERE [d] < DATEADD(month,3,GETDATE())
  ),
  allocations AS (
    SELECT *,SUM([Allocation %]) OVER(PARTITION BY [ResourceID],[d]) AS [Total Allocation %]
    FROM datelist
    INNER JOIN ResourceAssignment ON ([d] BETWEEN [Start Date] AND [End Date])
  )
SELECT *
FROM allocations
WHERE [Total Allocation %] >= 100

解决方案 2:在 ResourceAssignment 上使用具有自联接的范围冲突查询

SELECT *
FROM (
  SELECT
    t1.*,SUM(t1.[Allocation %]) OVER(PARTITION BY t1.[ResourceID]) AS [Total Allocation %]
  FROM ResourceAssignment t1
  INNER JOIN ResourceAssignment t2 ON (
    t1.[ResourceID] = t2.[ResourceID] AND
    t1.[ResourceAssignmentID] <> t2.[ResourceAssignmentID] AND
    t1.[Start Date] < t2.[End Date] AND
    t2.[Start Date] < t1.[End Date]
  )
  WHERE
    t1.[Start Date] <= CAST(GETDATE()+30 as date) AND
    t2.[Start Date] <= CAST(GETDATE()+30 as date) AND
    t1.[End Date] > CAST(GETDATE() as date) AND
    t2.[End Date] > CAST(GETDATE() as date)
) t
WHERE [Total Allocation %] >= 100

【讨论】:

【参考方案3】:

我认为这就是你想要达到的目标:

SELECT SUM(Allocation), ResourceID
FROM ResourceAssignment
WHERE EndDate BETWEEN GETDATE() AND  DATEADD(m,3,GETDATE())
GROUP BY ResourceID
HAVING SUM(Allocation) > 100

【讨论】:

【参考方案4】:

我假设开始日期和结束日期被格式化为日期时间或日期。

我不确定您是在尝试确定开始日期记录是在过去 3 个月内还是结束日期记录内。

您还需要一个限制来确定总和(分配百分比)。你想总结什么独特的记录。由于您想对分配百分比求和,然后只选择大于 100 的那些,因此您必须弄清楚要拉出哪些然后求和。

您需要使用 With 语句或创建分阶段提取所需信息的子“表”(查询)来完成此操作。我将介绍子查询语句。

为 Sql-Server 2008 R2 编写

首先选择过去 3 个月内的数据

Select ResourceAssignmentID, ResourceID, [Assigned To], [Allocation %]
From ResourceAssignment
Where [Start Date] >= dateadd(Month,-3,Now)

然后使用此数据对分配百分比求和。 (我假设基于 2 个外键的组合)

Select Query1.ResourceID, Query1.[Assigned To], sum(Query1.[Allocation %]) as Sumofallocation
From
(Select ResourceAssignmentID, ResourceID, [Assigned To], [Allocation %]
From ResourceAssignment
Where [Start Date] >= dateadd(Month,-3,Now)) Query1
Group By Query1.ResourceID, Query1.[Assigned To], sum(Query1.[Allocation %]) 

您可以在 group by 之前添加 Where 语句以过滤出您 >100 的要求,但我只需添加另一个 Select 语句即可将它们全部组合在一起

Select * From
(Select Query1.ResourceID, Query1.[Assigned To], sum(Query1.[Allocation %]) as Sumofallocation
From
(Select ResourceAssignmentID, ResourceID, [Assigned To], [Allocation %]
From ResourceAssignment
Where [Start Date] >= dateadd(Month,-3,Now)) Query1
Group By Query1.ResourceID, Query1.[Assigned To], sum(Query1.[Allocation %]) 
) Query2
Where Query2.Sumofallocation > 100

此外,您似乎正在从事项目管理类型的程序。微软项目不会工作吗?您将能够在您希望的任何时间范围内查看谁被过度分配。如果您有多个项目,您可以将它们合并到一个大的项目文件中并以这种方式查看...

无论如何,我希望这会有所帮助。 SQL 可能并不完美,但它应该为您指明一个可行的方向。

【讨论】:

以上是关于SQL 重叠日期范围的主要内容,如果未能解决你的问题,请参考以下文章

如何在 SQL 中选择重叠的日期范围

SQL Server 2014 合并重叠日期范围

PL/SQL:在由开始和结束定义的重叠日期范围内查找孤岛

在 oracle SQL 中基于重叠日期范围连接客户端记录

SQL中的重叠日期

sql时间范围查询重叠