当前位置:  开发笔记 > 后端 > 正文

比较日期范围

如何解决《比较日期范围》经验,为你挑选了2个好方法。

在MySQL中,如果我有一个日期范围列表(范围开始和范围结束).例如

10/06/1983 to 14/06/1983
15/07/1983 to 16/07/1983
18/07/1983 to 18/07/1983

我想检查另一个日期范围是否包含列表中已有的任何范围,我该怎么做?

例如

06/06/1983 to 18/06/1983 = IN LIST
10/06/1983 to 11/06/1983 = IN LIST
14/07/1983 to 14/07/1983 = NOT IN LIST

angry person.. 417

这是一个经典问题,如果你颠倒逻辑,它实际上更容易.

让我给你举个例子.

我会在这里发布一段时间,以及在某些方面重叠的其他时期的所有不同变化.

           |-------------------|          compare to this one
               |---------|                contained within
           |----------|                   contained within, equal start
                   |-----------|          contained within, equal end
           |-------------------|          contained within, equal start+end
     |------------|                       not fully contained, overlaps start
                   |---------------|      not fully contained, overlaps end
     |-------------------------|          overlaps start, bigger
           |-----------------------|      overlaps end, bigger
     |------------------------------|     overlaps entire period

另一方面,让我发布所有不重叠的内容:

           |-------------------|          compare to this one
     |---|                                ends before
                                 |---|    starts after

所以如果你简单地将比较减少到:

starts after end
ends before start

那么你会发现所有那些不重叠的东西,然后你会找到所有不匹配的时期.

对于最终的NOT IN LIST示例,您可以看到它符合这两个规则.

您将需要确定以下时段是否在您的范围内或在您的范围之外:

           |-------------|
   |-------|                       equal end with start of comparison period
                         |-----|   equal start with end of comparison period

如果你的表有名为range_end和range_start的列,这里有一些简单的SQL来检索所有匹配的行:

SELECT *
FROM periods
WHERE NOT (range_start > @check_period_end
           OR range_end < @check_period_start)

注意那里的NOT.由于两个简单的规则找到了所有不匹配的行,因此简单的NOT将反转它:如果它不是非匹配行之一,则它必须是匹配的行之一.

在这里应用简单的反转逻辑来摆脱NOT,你最终得到:

SELECT *
FROM periods
WHERE range_start <= @check_period_end
      AND range_end >= @check_period_start

我们需要一个"包含ACII图表"标志的答案,让您不止一次地对它们进行投票 (44认同)

可能是我在SO上看到的5个最佳答案之一.对问题的很好的解释,解决方案的精彩演练,以及...图片! (28认同)

如果我能不止一次投票,我愿意.对出现的常见问题进行了精彩,清晰和简洁的解释,这是我很少见到的解决方案! (10认同)

很棒的答案!我要添加的唯一内容 - 参考决定是否包含端点 - 如果你在一侧使用封闭间隔而在另一侧使用开放间隔,则一切都会更清晰.例如,范围的开始包括在该点中,并且范围的结束不包括.特别是当您处理日期和各种分辨率的时间组合时,一切都变得更加简单. (2认同)


Paul Dixon.. 8

以您的示例范围06/06/1983到18/06/1983为例,假设您的范围中包含名为startend的列,您可以使用这样的子句

where ('1983-06-06' <= end) and ('1983-06-18' >= start)

即,检查测试范围的开始是在数据库范围结束之前,并且测试范围的结束是在数据库范围之后或之后.



1> angry person..:

这是一个经典问题,如果你颠倒逻辑,它实际上更容易.

让我给你举个例子.

我会在这里发布一段时间,以及在某些方面重叠的其他时期的所有不同变化.

           |-------------------|          compare to this one
               |---------|                contained within
           |----------|                   contained within, equal start
                   |-----------|          contained within, equal end
           |-------------------|          contained within, equal start+end
     |------------|                       not fully contained, overlaps start
                   |---------------|      not fully contained, overlaps end
     |-------------------------|          overlaps start, bigger
           |-----------------------|      overlaps end, bigger
     |------------------------------|     overlaps entire period

另一方面,让我发布所有不重叠的内容:

           |-------------------|          compare to this one
     |---|                                ends before
                                 |---|    starts after

所以如果你简单地将比较减少到:

starts after end
ends before start

那么你会发现所有那些不重叠的东西,然后你会找到所有不匹配的时期.

对于最终的NOT IN LIST示例,您可以看到它符合这两个规则.

您将需要确定以下时段是否在您的范围内或在您的范围之外:

           |-------------|
   |-------|                       equal end with start of comparison period
                         |-----|   equal start with end of comparison period

如果你的表有名为range_end和range_start的列,这里有一些简单的SQL来检索所有匹配的行:

SELECT *
FROM periods
WHERE NOT (range_start > @check_period_end
           OR range_end < @check_period_start)

注意那里的NOT.由于两个简单的规则找到了所有不匹配的行,因此简单的NOT将反转它:如果它不是非匹配行之一,则它必须是匹配的行之一.

在这里应用简单的反转逻辑来摆脱NOT,你最终得到:

SELECT *
FROM periods
WHERE range_start <= @check_period_end
      AND range_end >= @check_period_start


我们需要一个"包含ACII图表"标志的答案,让您不止一次地对它们进行投票
可能是我在SO上看到的5个最佳答案之一.对问题的很好的解释,解决方案的精彩演练,以及...图片!
如果我能不止一次投票,我愿意.对出现的常见问题进行了精彩,清晰和简洁的解释,这是我很少见到的解决方案!
很棒的答案!我要添加的唯一内容 - 参考决定是否包含端点 - 如果你在一侧使用封闭间隔而在另一侧使用开放间隔,则一切都会更清晰.例如,范围的开始包括在该点中,并且范围的结束不包括.特别是当您处理日期和各种分辨率的时间组合时,一切都变得更加简单.

2> Paul Dixon..:

以您的示例范围06/06/1983到18/06/1983为例,假设您的范围中包含名为startend的列,您可以使用这样的子句

where ('1983-06-06' <= end) and ('1983-06-18' >= start)

即,检查测试范围的开始是在数据库范围结束之前,并且测试范围的结束是在数据库范围之后或之后.

推荐阅读
重庆制造漫画社
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有