如何比较一行中的重叠值?

时间:2008-12-30 05:08:01

标签: sql mysql overlap

我似乎对此SQL查询有问题:

SELECT * FROM appts 
WHERE timeStart >='$timeStart' 
AND timeEnd <='$timeEnd' 
AND dayappt='$boatdate'

时间格式为军事时间。物流是租船可以在早上7点至下午1点至下午1点或上午9点至下午5点预订。如果在该范围内有appt,它应该返回appts,但事实证明它不一致。如果我选择上午9点直到下午1点,它将忽略从早上7点开始的应用程序,即使它在上午9点到下午1点重叠。如果我选择9到5,它将返回任何内容,即使它应该在早上7点到下午1点。如何创建包含从timeStart到timeEnd的整个范围的SQL语句,包括那些重叠的?

4 个答案:

答案 0 :(得分:8)

Shahkalpesh回答了这个问题:

  

我认为你需要一个OR。

SELECT * FROM appts 
WHERE (timeStart >='$timeStart' 
OR timeEnd <='$timeEnd')
AND dayappt='$boatdate'

我发表了一条评论,我认为这是错误的,给出了一对反例:

  

这是完全错误的 - @ShaneD是正确的。例如,这将在05:00和06:00之间选择预订,因为实际结束时间少于您询问的任何结束时间。由于同等原因,它还将从18:00开始接收租金。

在回应我的评论时,Shahkalpesh要求:

  

你能发布一个单独的回复数据&amp;具有预期输出的输入参数?

足够公平 - 是的。略有编辑,问题说:

  

逻辑是可以预订船只租赁

  • 从早上7点到下午1点,或
  • 从上午9点到下午1点,或
  • 从上午9点到下午5点。
  

如果在该范围内有约会,它应该返回约会,但事实证明它是不一致的。如果我选择上午9点到下午1点,...


足够的背景。我们可以忽略约会的日期,只考虑时间。我假设有一种简单的方法可以将记录的时间限制为hh:mm格式;并非所有DBMS实际上都提供了这一点,但处理hh:mm:ss的扩展是微不足道的。

Appointments

Row     timeStart   timeEnd   Note
  1     07:00       13:00     First valid range
  2     09:00       13:00     Second valid range
  3     09:00       17:00     Third valid range
  4     14:00       17:00     First plausibly valid range
  5     05:00       06:00     First probably invalid range
  6     18:00       22:30     Second probably invalid range

鉴于搜索约会范围与09:00 - 13:00重叠,Shahkalpesh的(简化)查询变为:

SELECT * FROM Appointments
    WHERE (timeStart >= '09:00' OR timeEnd <= '13:00')

这将返回所有六行数据。但是,只有第1,2,3行与时间段09:00 - 13:00重叠。如果第1行,第2行和第3行是唯一有效的代表约会值,则Shahkalpesh的查询会生成正确的答案。但是,如果允许第4行(我认为合理有效),则不应返回。同样,不应返回第5行和第6行(如果存在)。 [实际上,对于表中的所有行假设 timeStart <= timeEnd (并且没有NULL值可以搞乱),我们可以看到Shahkalpesh的查询将返回任意数据行对于09:00-13:00查询,因为行的开始时间大于09:00或结束时间小于13:00或两者。这相当于在WHERE子句中编写 1 = 1 或任何其他重言式。]

如果我们考虑ShaneD的查询(简化):

SELECT * FROM Appointments
    WHERE timeStart <= '13:00' AND timeEnd >= '09:00'

我们看到它还选择第1,2和3行,但它拒绝第4行(因为timeStart&gt; '13:00'),5(因为timeEnd&lt; '09:00')和6(因为timeStart&gt; '13:00')。这个表达式是一个典型的例子,说明如何选择“重叠”,计数“满足”和“满足”(例如,参见“Allen's Interval Algebra”)重叠的行。更改'&gt; ='和'&lt; ='会更改计为重叠的间隔集。

答案 1 :(得分:6)

正确的检查如下:

SELECT * FROM appts 
WHERE timeStart <='$timeEnd' 
AND timeEnd >='$timeStart' 
AND dayappt='$boatdate'

已经给出了其他很好的解释,但我会继续更新它,并提供另一种解释,说明我是如何自己想象的。大多数人都在寻找每个可能的重叠,考虑到两个时间段,他们试图考虑可以使约会重叠的开始和结束的每个组合。我认为这是因为两个时间段没有重叠,因为某些原因对我来说更容易。

说我正在检查的时间段是今天,我想找到今天不重叠的任何时间段。实际上只有两种情况,即时间段在今天之后开始(PeriodStart&gt; EndOfToday)或时间段在今天之前结束(PeriodEnd&lt; StartOfToday)。

鉴于我们有一个不重叠的简单测试:
 (PeriodStart&gt; EndOfToday)或(PeriodEnd&lt; StartOfToday)

快速翻转,你有一个简单的重叠测试:
(PeriodStart&lt; = EndOfToday)AND(PeriodEnd&gt; = StartOfToday)

-Shane

答案 2 :(得分:0)

谢谢Shane,Shahkalpesh和Jonathan。

我实际上忽略了Shane“交换”变量的事实(我还在使用timeStart&lt; = $ timeStart,它应该是timeStart&lt; = $ timeEnd)。我按照Jonathan / Shane的建议运行修改后的声明并且它有效。正如乔纳森所指出的,我确实错过了一些我应该测试的时间范围。

现在有了Jonathan的解释,我现在可以更好地了解我的错误,这很有帮助。

答案 3 :(得分:-5)

我认为你需要一个OR。


SELECT * FROM appts 
WHERE (timeStart >='$timeStart' 
OR timeEnd <='$timeEnd')
AND dayappt='$boatdate'

假设每条记录仅关注特定日期。 租来的船只不会超过1天。