如何计算两个时间段重叠的持续时间

时间:2018-01-11 16:22:33

标签: sql sql-server

SELECT 
  Duration = Case
        When ([Start_Datetime] <= [MIN_START]) and [End_Datetime] Between [MIN_START] and [MAX_END] Then [MIN_START] - [End_Datetime]
        When ([Start_Datetime] <= [MIN_START]) and ([MIN_START] and [MAX_END] ) Between ([Start_Datetime] and [End_Datetime]) Then [MAX_END] - [MIN_START]
        When ([Start_Datetime] >= [MAX_END]) and [MAX_END] Between [Start_Datetime] and [End_Datetime] Then [MAX_END] - [Start_Datetime]
        When ([Start_Datetime] >= [MAX_END]) and ([Start_Datetime] and [End_Datetime] ) Between ([MIN_START] and [MAX_END] ) Then [End_Datetime] - [Start_Datetime]
        Else 0                                                           
From DB1


Example [Start_Datetime] [EndTime] [MIN_START][MAX_END] [Result]
    1          1              6         2          7        4 
    2          2              6         3          5        2 
    3          4              7         3          6        2  
    4          3              4         2          7        1 

我尝试使用And和Between My SQL错误 它说

  

在上下文中指定的非布尔类型的表达式   条件是预期的,靠近'和'。

我只是想知道如何纠正这个感谢

3 个答案:

答案 0 :(得分:0)

我认为在处理日期时间段交叉问题时可以将问题分解为方案。

在你的情况下,我们感兴趣的是这两个时期是否相交,如果是,那么相交的持续时间是多少:

Period 1 (Min_Start to Min_End)
Period 2 (Start_Datetime to End_Datetime)

Scenario1:

P1: <----------->
P2:                  <----------->

OR
P1:                  <----------->
P2: <------------>
Du: NULL

WHEN Min_End < Start_Datetime OR Min_Start > End_Datetime THEN NULL

--We can also check the opposite of this (Do these periods intersect?):

WHEN Min_End >= Start_Datetime AND Min_Start <= End_Datetime THEN --THEY INTERSECT! 

Scenario2:

P1: <---------------------------->
P2:      <--------------------------->
Du:      <----------------------->

WHEN Min_Start <= Start_Datetime AND Min_End <= End_DateTime THEN Min_End - Start_Datetime

场景3:

P1: <---------------------------->
P2:    <------------->
Du:    <------------->
WHEN Min_Start <= Start_Datetime and Min_End > End_Datetime THEN End_Datetime - Start_Datetime

Scenario4:

P1:    <----------------------->
P2: <------------->
Du:    <---------->
WHEN Min_Start > Start_Datetime AND Min_End > End_Datetime THEN End_Datetime - Min_Start

Scenario5:

P1:    <--------------->
P2: <------------------------->
Du:    <--------------->
When Min_Start > Start_Datetime AND Min_End < End_Datetime Then Min_End - Min_Start

这可以写成:

CASE 
    /*S1: Do they intersect?*/
    WHEN Min_End >= Start_Datetime AND Min_Start <= End_Datetime 
        THEN                
            CASE 
                /*S2*/ WHEN Min_Start <= Start_Datetime AND Min_End <= End_DateTime THEN DATEDIFF(day, Start_Datetime, Min_End)
                /*S3*/ WHEN Min_Start <= Start_Datetime and Min_End > End_Datetime THEN DATEDIFF(day, Start_Datetime, End_Datetime)
                /*S4*/ WHEN Min_Start > Start_Datetime AND Min_End > End_Datetime THEN DATEDIFF(day, Min_Start, End_Datetime)
                /*S5*/ WHEN Min_Start > Start_Datetime AND Min_End < End_Datetime THEN DATEDIFF(day, Min_Start, Min_End)
                END
    END

希望这是正确的。这些东西总是让我感到困惑;)

答案 1 :(得分:0)

问题出在你的最后一个条件:

 When ([Start_Datetime] >= [MAX_END])
  and ([Start_Datetime] and [End_Datetime] )
 Between ([MIN_START] and [MAX_END] )
        Then [End_Datetime] - [Start_Datetime]
        Else 0     

您希望通过Between ([MIN_START] and [MAX_END] )

实现什么目标?

这没有意义,也许你的意思是:

When ([Start_Datetime] >= [MAX_END]) 
and ([Start_Datetime] Between [MIN_START] and [MAX_END]) 
and ([End_Datetime] Between [MIN_START] and [MAX_END]) 
Then [End_Datetime] - [Start_Datetime]

这是最后一个条件

答案 2 :(得分:0)

要确定范围的开始/结束,您只需要将最大开始日期与最小结束日期进行比较。这是一个测试值与问题中的值匹配的示例。

DECLARE @duration1_start INT, @duration1_end INT, @duration2_start INT, @duration2_end INT

-- Test 1: Returns 4
SELECT @duration1_start = 1, @duration1_end = 6, @duration2_start = 2, @duration2_end = 7 
-- Test 2: Returns 2
SELECT @duration1_start = 2, @duration1_end = 6, @duration2_start = 3, @duration2_end = 5 
-- Test 3: Returns 2
SELECT @duration1_start = 4, @duration1_end = 7, @duration2_start = 3, @duration2_end = 6 
-- Test 4: Returns 1
SELECT @duration1_start = 3, @duration1_end = 4, @duration2_start = 2, @duration2_end = 7 

SELECT (SELECT MIN(en) FROM (SELECT @duration1_end AS en UNION SELECT @duration2_end)sq) -
(SELECT MAX(st) FROM (SELECT @duration1_start AS st UNION SELECT @duration2_start)sq)

相反,如果您确实想使用datetime字段,可以使用:

DECLARE @duration1_start DATETIME, @duration1_end DATETIME, @duration2_start DATETIME, @duration2_end DATETIME

-- Test 1: Returns 4
SELECT @duration1_start = '1/1/2018', @duration1_end = '1/6/2018', @duration2_start = '1/2/2018', @duration2_end = '1/7/2018' 
-- Test 2: Returns 2
SELECT @duration1_start = '1/2/2018', @duration1_end = '1/6/2018', @duration2_start = '1/3/2018', @duration2_end = '1/5/2018' 
-- Test 3: Returns 2
SELECT @duration1_start = '1/4/2018', @duration1_end = '1/7/2018', @duration2_start = '1/3/2018', @duration2_end = '1/6/2018' 
-- Test 4: Returns 1
SELECT @duration1_start = '1/3/2018', @duration1_end = '1/4/2018', @duration2_start = '1/2/2018', @duration2_end = '1/7/2018' 

SELECT DATEDIFF(DAY, 
(SELECT MAX(st) FROM (SELECT @duration1_start AS st UNION SELECT @duration2_start)sq), 
(SELECT MIN(en) FROM (SELECT @duration1_end AS en UNION SELECT @duration2_end)sq))

如果没有交叉点,您将获得一个负数,因为最大起始值大于最小值。您可以使用case语句处理该场景:

-- Test 5: Returns -1
SELECT @duration1_start = 3, @duration1_end = 4, @duration2_start = 5, @duration2_end = 6 

SELECT CASE WHEN diff < 0 THEN NULL ELSE diff END
FROM
(
    SELECT (SELECT MIN(en) FROM (SELECT @duration1_end AS en UNION SELECT @duration2_end)sq) -
    (SELECT MAX(st) FROM (SELECT @duration1_start AS st UNION SELECT @duration2_start)sq) AS diff
)sq