Странность MySQL с датами и МЕЖДУ

Я запускаю запрос, чтобы получить строки, которые попадают между определенными датами (текущая дата и 7 дней назад для этого примера).

Я пробовал писать так:

SELECT * 
FROM faulttracker.ft_v_cases 
WHERE DATE(cs_created) BETWEEN DATE(NOW()) AND DATE(NOW()-INTERVAL 7 DAY) 
ORDER BY cs_created DESC;

но он вернул 0 строк. Я не мог понять, почему это не сработало, и попытался переписать это так:

SELECT * 
FROM faulttracker.ft_v_cases 
WHERE DATE(cs_created) <= DATE(NOW()) 
AND DATE(cs_created) >= DATE(NOW()-INTERVAL 7 DAY) 
ORDER BY cs_created DESC;

который ДЕЙСТВИТЕЛЬНО работал.

Почему первый вернул 0 строк, а второй работал как положено? Насколько я понимаю, они должны быть функционально эквивалентны.

cs_created — это дата и время.


person GordonM    schedule 08.02.2011    source источник


Ответы (5)


Согласно документации, BETWEEN ожидает следующее: формат:

 expr BETWEEN min AND max

В вашем первом примере вы ставите минимальное значение последним.

Попробуйте использовать:

SELECT * 
FROM faulttracker.ft_v_cases 
WHERE DATE(cs_created) BETWEEN DATE(NOW()-INTERVAL 7 DAY) AND DATE(NOW()) 
ORDER BY cs_created DESC;
person Matt Healy    schedule 08.02.2011
comment
Ты прав! Думаю, сегодня утром у меня было угасание мозга, и я полностью пропустил это. - person GordonM; 08.02.2011

Я почти уверен, что вы можете так же использовать:

WHERE cs_created >= CURDATE() - INTERVAL 7 DAY 
  AND cs_created <  CURDATE() + INTERVAL 1 DAY

Это должно вернуть те же результаты, но также разрешить запросу использовать индекс для cs_created.

person Mchl    schedule 08.02.2011
comment
Как вы думаете, почему другие формулировки не позволяют использовать индекс? - person Jonathan Leffler; 08.02.2011
comment
@Jonathan Leffler: потому что другие решения используют функцию в столбце cs_created. MySQL не использует индекс в таком случае (поскольку ему нужно вычислить результат функции) - person Mchl; 08.02.2011
comment
+1 за упоминание об использовании индекса. И вы также можете использовать константу CURRENT_DATE вместо функции CURDATE(). CURRENT_DATE работает и во многих других СУБД, это стандарт SQL. - person Frank Heikens; 08.02.2011

Ваше состояние должно быть -

WHERE DATE(cs_created) BETWEEN DATE(NOW()-INTERVAL 7 DAY) AND DATE(NOW())

Нижнее значение даты должно быть слева при использовании Между.

person Sachin Shanbhag    schedule 08.02.2011

Вы всегда должны иметь диапазон, работающий как BETWEEN smaller AND larger; лечение одинаково независимо от того, пишете ли вы:

x BETWEEN smaller AND larger
x >= smaller AND x <= larger

Следовательно, ваш код с использованием BETWEEN должен быть написан как:

SELECT * 
  FROM faulttracker.ft_v_cases 
 WHERE DATE(cs_created) BETWEEN DATE(NOW() - INTERVAL 7 DAY) AND DATE(NOW())
 ORDER BY cs_created DESC;

Конечно, это охватывает последние 8 дней, поскольку диапазон с BETWEEN/AND включен.

person Jonathan Leffler    schedule 08.02.2011

вы пробовали поставить так:

SELECT * FROM faulttracker.ft_v_cases WHERE CAST(cs_created AS DATE) BETWEEN CAST(NOW() AS DATE) AND CAST(DATE(NOW()-INTERVAL 7 DAY) AS DATE) ORDER BY cs_created DESC;

руководство гласит:

для достижения наилучших результатов при использовании BETWEEN со значениями даты или времени используйте CAST() для явного преобразования значений в желаемый тип данных.

person NDM    schedule 08.02.2011
comment
Использование CAST для значений, которые уже являются значениями DATE, кажется излишним, и это не является источником проблемы. - person Jonathan Leffler; 08.02.2011