使用 SQL 条件检查时间间隔

Posted

技术标签:

【中文标题】使用 SQL 条件检查时间间隔【英文标题】:Check time interval using SQL condition 【发布时间】:2011-03-12 11:08:39 【问题描述】:

我在 SQL 中存储了一些区间,例如:

id INT
from DATE
to DATE

如果新间隔与现有间隔冲突,我如何仅使用一个条件(如果可能)检查?

例子:

|-----------| (from 1 to 5)
    |-----------| (from 2 to 6)
       |--| (from 3 to 4)
                   |--| (from 7 to 8)

每个间隔(前三个)都与其他两个间隔有一些冲突......除了最后一个单独的间隔。

--

可以使用以下条件来实现此检查:

WHERE (`from` <= $FROM and `to` >= $TO)

但这仅检查包含新的间隔...而不是具有某些交叉点内部的其他间隔新的。

也许是这样的?

WHERE NOT (`from` < $FROM and `to` < $TO) AND NOT (`from` > $FROM and `to` > $TO)

Obs.:我需要找到冲突以提醒用户这个新时期已经存在或与现有时期发生冲突。

【问题讨论】:

您使用什么表示周期,例如封闭开放?换句话说,你会认为(from 1 to 5)(from 5 to 6) 发生冲突吗? 【参考方案1】:

我遇到了这个问题,只是想尝试展示真值表如何识别 Paul 已经发布的简化逻辑。

假设您有一个区间from [ to ],您想对照from to 进行检查。

这转化为以下真值表:

 #   [ <    [ <    ] <    ] <     Collision?  Example
 1     T       T       T       T          F       [ ]  
 2     T       T       T       F          T       [   ] *
 3     T       T       F       T          T       [  ] 
 4     T       T       F       F          T       [   ]
 5     T       F       T       T          T       ]  [  *
 6     T       F       T       F          T        [ ]  *
 7     T       F       F       T          Contradiction
 8     T       F       F       F          T        [  ] *
 9     F       T       T       T          T       ]  [  *
10     F       T       T       F          Contradiction
11     F       T       F       T          T        [ ] 
12     F       T       F       F          T        [  ]
13     F       F       T       T          T       ]   [ *
14     F       F       T       F          T        ]  [ *
15     F       F       F       T          T        ]  [ *
16     F       F       F       F          F         [ ]

查看这个真值表,识别冲突的最简单表达式是:

NOT ( [ &lt; AND [ &lt; AND ] &lt; AND ] &lt; ) AND NOT ( [ &gt;= AND [ &gt;= AND ] &gt;= AND ] &gt;= )

但是我们知道,由于 &lt; [ &lt; ],这简化为

NOT ( [ &lt; AND ] &lt; ) AND NOT ( [ &gt;= AND ] &gt;= )

对应的SQL:

WHERE NOT ('from' &lt; $FROM and 'to' &lt; $FROM ) AND NOT ('from' &gt; $TO and 'to' &gt; $TO)(类似于@TiuTalk 的建议)。

但是,我们已经假设 &lt; [ &lt; ]。这很关键。查看真值表中标记为* 的行。在这些行中, &lt; ] &lt; [。我们知道那些不会发生。另外,有些行暗示了完全矛盾的事情,比如 &lt; AND &lt; ,我们知道这是不可能的。消除所有这些行只得到 6 行:

 #   [ <    [ <    ] <    ] <     Collision?  Example
 1     T       T       T       T          F       [ ]  
 3     T       T       F       T          T       [  ] 
 4     T       T       F       F          T       [   ]
11     F       T       F       T          T        [ ] 
12     F       T       F       F          T        [  ]
16     F       F       F       F          F         [ ]

在这里,我们可以看到只有中间的两个子句确定是否存在冲突。即( [ &lt; ) AND NOT ( ] &lt; )。这相当于( [ &lt; ) AND ( ] &gt;= )(否定第二个比较器),相当于SQL WHERE ('from' &lt; $TO AND 'to' &gt;= $FROM)。这在语义上等同于 Paul 的条款(除非通过 &lt;= 一直工作到最后)。

【讨论】:

【参考方案2】:
WHERE ($TO >= `from` AND $FROM <= `to`)

请注意,这适用于新范围与整个范围重叠、仅部分重叠以及包含它的情况。

【讨论】:

我曾在 80 年代从事 GIS 系统工作。交叉和重叠是我的第二天性。

以上是关于使用 SQL 条件检查时间间隔的主要内容,如果未能解决你的问题,请参考以下文章

Oracle中按照时间范围以及时间间隔抽取数据的问题

以毫秒为间隔检测秒数

后台 iBeacon 检查间隔

检查一个列表的间隔是不是与另一个列表的间隔重叠

使用SQL计算宝宝每次吃奶的时间间隔(数据保障篇)

检查时间间隔是不是在今天