【问题标题】:How do I calculate the duration that two time periods overlap如何计算两个时间段重叠的持续时间
【发布时间】:2018-01-12 06:05:12
【问题描述】:
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 and Between My SQL 错误 它说

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

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

【问题讨论】:

  • ([Start_Datetime] &lt;= [MIN_START]) and ([MIN_START] and [MAX_END] ) Between ([Start_Datetime] and [End_Datetime]) Then [MAX_END] - [MIN_START] 这是无效的。你想达到什么目的
  • ([MIN_START] and [MAX_END] ) Between 没有意义。您一次只能检查一个字段是否介于其他字段之间。您可能需要两个 BETWEEN 语句,一个用于这两个日期中的每一个,它们之间有一个 AND。
  • 不相关 - 你缺少一个 END。
  • 我正在尝试计算 2 时间范围 EX:开始时间 4 -10 之间的重叠持续时间。结束时间 3-5。重叠 1 小时
  • BETWEEN 不应与括号一起使用

标签: sql sql-server


【解决方案1】:

我认为在处理日期时间段交叉问题时将问题分解为场景会有所帮助。

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

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

场景1:

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! 

场景2:

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

场景4:

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

场景5:

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

希望这是正确的。这些事情总是让我很困惑;)

【讨论】:

  • 抱歉打错了,我的意思是 max_end。
  • WHEN Cast(T1.[Start_Datetime] AS datetime) = T2.[MAX_END] OR [End_Datetime] = Cast(T2.[MIN_START] AS datetime) THEN 0 此代码适用于时间范围背靠背时
  • @SQLNOOB 这很好。我只针对经期交叉点,那就是经期会议。然后是场景 6 :)
【解决方案2】:

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

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)

相反,如果你真的想使用日期时间字段,你可以使用这个:

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

【讨论】:

    【解决方案3】:

    问题是你最后的情况:

     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]
    

    这是最后一个条件

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-28
      • 2015-10-30
      • 2021-01-03
      • 1970-01-01
      相关资源
      最近更新 更多