有没有办法添加自动获取日期的日期差值?

时间:2019-08-19 17:47:03

标签: sql sql-server

我想做的是我有两个日期,并使用DateDiff来获取两个日期之间的差值。例如,我已经计划了Start Dateactual start Date,而我得到的这个日期之间的差是5,现在我想把这一天添加到Finish date中。

如果我的Finish date不是我想的,而是我想的,那么我想补充一下这个差值,并想找到下一个finish date,因为我们在下一个即将到来的日期后面。

Sum (DATEDIFF(day, sa.PlannedStartDate, sa.ActualStartDate)) OVER 
  (Partition 
    By ts.Id)as  TotalVariance,
     Case when (Sum (DATEDIFF(day, sa.PlannedStartDate, sa.ActualStartDate)) 
   OVER 
  (Partition By ts.Id) >30) then 'Positive' end as Violation,
  DATEADD (day, DATEDIFF(day, sa.PlannedStartDate, sa.ActualStartDate))as 
  Summar violations,

如果活动 1 -planned Start date8/21/2019,但是actual start date9/21/2019,那么在这种情况下,我们落后了30天。 / p>

现在下一个活动将被延迟,因此我想将此差异添加到下一个活动中。

如果第二项活动planned Start date08/25/2019,但是由于活动1的延迟,start date将更改为第二项活动,在这种情况下,我想查找该新日期。

  Activity   PlannedStartdate  ActualStartDate  Variance NewPlannedstartdate
  Activity 1  8/21/2019         9/21/2019           30
  Acivity  2  8/26/2019         null                        9/26/2019

1 个答案:

答案 0 :(得分:1)

以下是您可以在SSMS中运行的示例:

-- CREATE ACTIVITY TABLE AND ADD SOME DATA --
DECLARE @Activity TABLE ( ActivityId INT, PlannedStart DATE, ActualStart DATE );

INSERT INTO @Activity ( 
    ActivityId, PlannedStart, ActualStart 
)
VALUES 
( 1, '08/21/2019', '08/27/2019' ), ( 1, '08/26/2019', NULL ), ( 1, '09/14/2019', NULL );

查询@Activity以查看其中的内容:

SELECT * FROM @Activity ORDER BY ActivityId, PlannedStart;

@活动内容:

+------------+--------------+-------------+
| ActivityId | PlannedStart | ActualStart |
+------------+--------------+-------------+
|          1 | 2019-08-21   | 2019-08-27  |
|          1 | 2019-08-26   | NULL        |
|          1 | 2019-09-14   | NULL        |
+------------+--------------+-------------+

查询@Activity以考虑新的开始日期:

;WITH Activity_CTE AS (
    SELECT
        ROW_NUMBER() OVER ( ORDER BY PlannedStart ) AS Id,
        ActivityId, PlannedStart, ActualStart, DATEDIFF( dd, PlannedStart, ActualStart ) Delayed
    FROM @Activity
    WHERE
        ActivityId = @ActivityId
)
SELECT
    ActivityId,
    PlannedStart,
    ActualStart,
    DATEADD( dd, Delays.DaysDelayed, PlannedStart ) AS NewStart
FROM Activity_CTE AS Activity
OUTER APPLY (
    SELECT CASE
        WHEN ( Delayed IS NOT NULL ) THEN Delayed
        ELSE ISNULL( ( SELECT TOP 1 Delayed FROM Activity_CTE WHERE Id < Activity.Id AND Delayed IS NOT NULL ORDER BY Id DESC ), 0 )
    END AS DaysDelayed
) AS Delays
ORDER BY
    PlannedStart;

返回

+------------+--------------+-------------+------------+
| ActivityId | PlannedStart | ActualStart |  NewStart  |
+------------+--------------+-------------+------------+
|          1 | 2019-08-21   | 2019-08-27  | 2019-08-27 |
|          1 | 2019-08-26   | NULL        | 2019-09-01 |
|          1 | 2019-09-14   | NULL        | 2019-09-20 |
+------------+--------------+-------------+------------+

这里真正的“魔术”是这一行:

ELSE ISNULL( ( SELECT TOP 1 Delayed FROM Activity_CTE WHERE Id < Activity.Id AND Delayed IS NOT NULL ORDER BY Id DESC ), 0 )

它正在检查自身是否有延迟的任何先前记录。如果未找到,则返回0。然后使用此值将日期添加到 PlannedStart 日期,以确定 NewStart 日期。 ORDER BY也特别值得注意。按DESC顺序排序可确保我们在当前行之前获得“最近”延迟。

以这种方式使用CTE还考虑了可能不会在第一条记录上发生延迟的想法(例如,说计划的08/26已延迟而不是08/21)。它方便地为我们提供了一个子表,可在我们的外部应用程序中进行查询。

如果您将CTE的SELECT中的所有列都包括在内,就会看到以下内容:

+----+------------+--------------+-------------+---------+-------------+
| Id | ActivityId | PlannedStart | ActualStart | Delayed | DaysDelayed |
+----+------------+--------------+-------------+---------+-------------+
|  1 |          1 | 2019-08-21   | 2019-08-27  | 6       |           6 |
|  2 |          1 | 2019-08-26   | NULL        | NULL    |           6 |
|  3 |          1 | 2019-09-14   | NULL        | NULL    |           6 |
+----+------------+--------------+-------------+---------+-------------+

因为第一个记录是唯一一个延迟的记录,所以它的6天延迟在以下每个记录中一直存在。