查找mysql中最近的空闲时间段的查询 - 为什么它不起作用?

时间:2015-11-13 08:37:34

标签: mysql sql

我有一个名为notes的表格,我有三个字段:

id  |      start_time       |  duration
 1  |  2015-10-21 19:41:35  |    15
 2  |  2015-10-21 19:41:50  |    15
 3  |  2015-10-21 19:42:05  |    15
 4  |  2015-10-21 19:42:35  |    15
etc.

id是INT字段

start_time是TIMESTAMP字段

duration是INT字段,它表示每个事件的持续时间。

我正在编写一个SQL查询,将3个字段作为输入:durationbegin_timeend_time并返回timestamp字段甚至新的甚至可以适合的地方。

基于StackOverflow上类似于我的许多问题(主要是这个特别的MySQL / PHP - Find available time slots),我创建了一个查询:

SELECT (a.start_time + a.duration) AS free_after FROM notes a
WHERE NOT EXISTS ( SELECT 1 FROM notes b
WHERE b.start_time BETWEEN (a.start_time+a.duration) AND
(a.start_time+a.duration) + INTERVAL '$duration' SECOND) AND 
(a.start_time+a.duration) BETWEEN '$begin_time' AND '$end_time'

但是当我按照以下方式运行时:

SELECT (a.start_time + a.duration) AS free_after FROM notes a
WHERE NOT EXISTS ( SELECT 1 FROM notes b WHERE b.start_time
BETWEEN (a.start_time+a.duration) AND (a.start_time+a.duration) + INTERVAL 15 SECOND )
AND (a.start_time+a.duration) BETWEEN '2015-11-21 19:41:30' AND '2015-11-21 19:43:50'

我没有找到任何记录,即使 - 看看上面提到的表格 - 我应该得到一个结果:

     free_after 
2015-11-21 19:42:20

(因为在这两个记录之间:

 3  |  2015-10-21 19:42:05  |    15
 4  |  2015-10-21 19:42:35  |    15

有15秒的空闲时段。那么为什么我的查询无法正常工作?

====编辑:

在遵循理查德的建议后,我做了一个show warnings查询,它返回了我的值:

Truncated incorrect DOUBLE value: '2015-11-21 19:4...
Truncated incorrect DOUBLE value: '2015-11-21 19:4...
Truncated incorrect DOUBLE value: '2015-11-21 19:4...
Truncated incorrect DOUBLE value: '2015-11-21 19:4...
Incorrect datetime value: '0'

我不知道是什么原因造成的,你能帮帮我吗?

=====编辑2

好的,按照@ Richard的另一个建议(谢谢顺便说一句!)后,我将查询改为以下内容:

SELECT (a.start_time + INTERVAL a.duration SECOND) AS free_after FROM notes a
WHERE
NOT EXISTS ( SELECT 1 FROM notes b WHERE b.start_time
BETWEEN (a.start_time + INTERVAL a.duration SECOND) AND
(a.start_time + INTERVAL a.duration SECOND) + INTERVAL 15 SECOND ) AND
(a.start_time + INTERVAL a.duration SECOND) BETWEEN '2015-11-21 19:41:30' AND '2015-11-21 19:43:50'

这次我得到了一个结果(这是一条好消息):

2015-10-21 19:42:50

但这是一个糟糕的价值(这是一个更糟糕的消息)。它应该是2015-10-21 19:42:20 ......我还有什么别的错吗?当我在它之后show warnings之后 - 在这里没有更多的东西:(

4 个答案:

答案 0 :(得分:2)

BETWEEN子句完全匹配结束日期。使用样本数据,一旦添加15秒的持续时间和固定的持续时间(也为15秒),它将与您30秒开启的最后一个样本数据相匹配,从而排除。将您的查询修改为

SELECT (a.start_time + INTERVAL a.duration SECOND) AS free_after FROM notes a
WHERE
NOT EXISTS ( SELECT 1 FROM notes b WHERE b.start_time
BETWEEN (a.start_time + INTERVAL a.duration SECOND) AND
(a.start_time + INTERVAL a.duration SECOND) + INTERVAL 15 SECOND - INTERVAL 1 MICROSECOND) AND
(a.start_time + INTERVAL a.duration SECOND) BETWEEN '2015-10-21 19:41:30' AND '2015-10-21 19:43:50'

(即取消1微秒作为调整)

你得到了答案:

+---------------------+
| free_after          |
+---------------------+
| 2015-10-21 19:42:20 |
| 2015-10-21 19:42:50 |
+---------------------+
2 rows in set (0.00 sec)

答案 1 :(得分:1)

简短回答:因为您无法将TIMESTAMP添加到INT

例如参见:How to add an offset to all timestamps/DATETIME in a MySQL database?

答案很长:

作为调试复杂SQL查询的一般规则,从一个更简单的表单开始,然后逐个添加更复杂的子句,直到它停止执行您期望的操作,然后修复它。在您的情况下,从

开始
SELECT (a.start_time + a.duration) AS free_after FROM notes a;

当我在我的系统上尝试时,会给出:

+----------------+
| free_after     |
+----------------+
| 20151021194150 |
| 20151021194165 |
| 20151021194220 |
| 20151021190250 |
+----------------+

这些对我来说看起来不像普通的DATETIMETIMESTAMP。我注意到,在一个地方,您的查询会使用INTERVAL <value> SECOND表示法向TIMESTAMP添加偏移量,但在所有其他添加项中忽略了这一点。

mysql> SELECT (a.start_time + INTERVAL a.duration SECOND) AS free_after FROM notes a;
+---------------------+
| free_after          |
+---------------------+
| 2015-10-21 19:41:50 |
| 2015-10-21 19:42:05 |
| 2015-10-21 19:42:20 |
| 2015-10-21 19:02:50 |
+---------------------+
4 rows in set (0.00 sec)

看起来更好。始终遵循相同的原则,完整查询给出了预期的结果。

另外,正如理查德评论的那样,您应该看到报告的警告。在mysql中使用show warnings;会给你一个类似的线索,抱怨“日期时间值不正确”和“截断错误的DOUBLE值”。

答案 2 :(得分:0)

您无法在日期中添加int。试试这个:

    SELECT notes.starttime+ INTERVAL notes.duration SECOND
FROM notes
WHERE notes.starttime+INTERVAL notes.duration SECOND<= '2015-11-21 19:41:30'
  AND NOT EXISTS (SELECT notes.id 
      FROM notes 
      WHERE notes.starttime <= '2015-11-21 19:43:50'
        AND notes.starttime+ INTERVAL notes.duration SECOND>='2015-11-21 19:43:50')
ORDER BY notes.starttime

答案 3 :(得分:0)

您可以模拟LAG()函数和......:

  • 首先。计算当前行和最后一行之间的差异
  • 二。选择diff大于持续时间的行

试试这个SQL:

SET @lag_time='0000-00-00 00:00:00';
SELECT TIMESTAMPADD( SECOND, duration, lastTime ) as fromTime,
       (diffTime - duration) freeSeconds,
       currTime toTime
FROM
  (SELECT @lag_time as LastTime, 
         IFNULL(TIMESTAMPDIFF(SECOND, @lag_time, start_time ),0) diffTime,
         @lag_time:=start_time currTime,
         duration       
  FROM notes) as TimeDiff
WHERE diffTime > duration
ORDER BY currTime;