我有一个名为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个字段作为输入:duration
,begin_time
和end_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
之后 - 在这里没有更多的东西:(
答案 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 |
+----------------+
这些对我来说看起来不像普通的DATETIME
或TIMESTAMP
。我注意到,在一个地方,您的查询会使用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()函数和......:
试试这个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;