У меня есть таблица под названием 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 - найти доступные временные интервалы) Я создал запрос:
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 секунд). Итак, почему мой запрос не работает должным образом?
==== EDIT:
После рекомендации Ричарда я сделал запрос 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 (спасибо btw!), я изменил свой запрос на следующий:
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
сразу после него - здесь больше ничего нет: (
Предложение 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)
Короткий ответ: потому что вы не можете просто добавить TIMESTAMP
в INT
.
См. например: Как добавить смещение во все временные метки /DATETIME в базе данных MySQL?
Длинный ответ:
Как правило, при отладке сложного 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)
Это выглядит лучше. Следуя тому же принципу, полный запрос дает ожидаемый результат.
Кроме того, как заметил Ричард, вы должны были видеть предупреждения. Использование show warnings;
в mysql тогда дало бы вам подобный ключ, жалуясь на "Неверное значение даты и времени" и "Усеченное неправильное значение DOUBLE".
2015-10-21 19:42:20
, так что, должно быть, что-то другое на вашей стороне?
Вы не можете добавить 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
Вы можете имитировать функцию 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;
show warnings;
в нем перечислены проблемы с вашим запросом.start_time
является меткой времени, и мне, вероятно, придется изменить свой запрос для работы с метками времени, а не с датой, но я не знаю точно, как это исправить, не могли бы вы помочь мне с этим? Пожалуйста, проверьте мои правки на оригинальный вопрос, спасибо!