MySQL между предложением не включает?

Если я запускаю запрос с предложением between, он, кажется, исключает конечное значение.
Например:

select * from person where dob between '2011-01-01' and '2011-01-31'

Это дает все результаты с dob от '2011-01-01' до '2011-01-30'; пропуск записей, где dob - «2011-01-31». Может ли кто-нибудь объяснить, почему этот запрос ведет себя таким образом, и как я могу изменить его, чтобы включить записи, где dob - «2011-01-31»? (без добавления 1 к дате окончания, потому что она была выбрана пользователями.)


person ASD    schedule 22.02.2011    source источник
comment
Неа. Моя установка MySQL (версия?) BETWEEN включает оба значения. У меня MySQL Server 5.7 на Windows 10.   -  person Green    schedule 18.09.2017


Ответы (10)


Поле dob, вероятно, имеет компонент времени.

Чтобы усечь его:

select * from person 
where CAST(dob AS DATE) between '2011-01-01' and '2011-01-31'
person tiago2014    schedule 22.02.2011
comment
Вместо CAST(dob AS DATE) вы можете использовать более лаконичный DATE(dob). - person jkndrkn; 30.09.2011
comment
Хотя это работает, вы получите лучшую производительность, если будете использовать >= и < вместо between. - person David Harkness; 20.03.2012
comment
Вы получите лучшую производительность, используя dob BETWEEN '2011-01-01 00:00:00' AND '2011-01-31 23:59:59. Это связано с тем, что DATE(dob) должен вычислять значение для каждой строки и не может использовать какие-либо индексы в этом поле. - person joshuahedlund; 31.07.2012
comment
@joshuahedlund Пожалуйста, добавьте ответ с этим решением. CAST не так эффективен. - person doc_id; 27.05.2015
comment
@joshuahedlund Это работает, пока у вас не будут данные со временем t > 23:59:59 and t < 24:00:00. Зачем вообще иметь дело с плохо определенным BETWEEN? Скорее следуйте совету Дэвида и используйте: WHERE dob >= '2011-01-01' AND dob < '2011-02-01'. Лучшая производительность, и она работает каждый раз. - person Disillusioned; 27.02.2017
comment
@DavidHarkness, почему ты так думаешь? Пожалуйста, уточните это подробнее. - person Green; 18.09.2017
comment
@Green, чтобы избежать затрат на преобразование и получить скорость индексации в поле, как пояснили Джошуахедлунд и Крейг Янг. Возможно, MySQL оптимизирует подобные запросы, чтобы они были эквивалентными. - person David Harkness; 19.09.2017
comment
@joshuahedlund Я обнаружил, что когда я использую этот SELECT * FROM sales WHERE created >= '2020-01-09 00:00:00' AND created <= '2020-01-09 11:59:59' AND store_id=3, он не выбирает данные, но когда я использую этот SELECT * FROM sales WHERE DATE(created) >= '2020-01-09 00:00:00' AND DATE(created) <= '2020-01-09 11:59:59' AND store_id=3, он возвращает данные. поле даты - datetime, вы знаете, почему это происходит? - person Smith; 15.01.2020

Из руководства по MySQL:

Это эквивалентно выражению (min ‹= expr AND expr‹ = max)

person Frank Heikens    schedule 22.02.2011
comment
Руководство, связанное с этим ответом, показывает, что приведение предпочтительнее при сравнении объектов DATE и DATETIME. Так что я думаю, что у @tiagoinu есть наиболее полный ответ в самом строгом смысле, но оба точны. - person Kingsolmn; 05.03.2013
comment
@jemminger может быть потому, что ответ от archrival -postgres guy: P - person nawfal; 17.06.2013
comment
Короче говоря, между включительно ... вот почему этот ответ потрясает. - person Rafael; 08.03.2015
comment
Старый комментарий, но я хотел привязать его к конкретному запросу. BETWEEN является включительно, но даты без указания времени дополняют до 00:00:00. Таким образом, сравнение по диапазону дат приведет к потере последнего дня. Либо позвоните DATE (dob), либо укажите конец дня. - person wintermute92; 20.09.2016
comment
они говорят, что практика - это золото, исходя из моего варианта использования, она не является всеобъемлющей, мне интересно, почему это происходит со мной. Я пробовал, и иногда это работает, иногда нет. используя его в поле данных TIME. - person Jeffery ThaGintoki; 21.08.2018

Проблема в том, что 2011-01-31 на самом деле - это 2011-01-31 00:00:00. Это начало дня. Все в дневное время не входит.

person Daniel Hilgarth    schedule 22.02.2011
comment
Это действительно объясняет, что происходит, и отвечает на вопрос. - person Ivan P; 03.01.2014
comment
После стольких лет этот ответ по-прежнему остается лучшим. Большое спасибо. - person Strabek; 25.02.2017

Является ли поле, на которое вы ссылаетесь в своем запросе, тип Дата или тип Дата и время?

Распространенной причиной описываемого поведения является использование типа DateTime, в котором действительно следует использовать тип Date. То есть, если вам действительно не нужно знать, в какое время кто-то родился, просто используйте тип Date.

Причина, по которой последний день не включается в ваши результаты, заключается в том, что запрос принимает временную часть дат, которую вы не указали в своем запросе.

То есть: ваш запрос интерпретируется как до полуночи между 30 января 2011 года и 31 января 2011 года, но данные могут иметь значение днем ​​позже 31 января 2011 года.

Предложение: измените поле на тип Date, если это тип DateTime.

person JohnFx    schedule 22.02.2011

Привет, этот запрос работает для меня,

select * from person where dob between '2011-01-01' and '2011-01-31 23:59:59'
person infinito84    schedule 09.12.2013

select * from person where DATE(dob) between '2011-01-01' and '2011-01-31'

Удивительно, но такие преобразования - решение многих проблем в MySQL.

person betty.88    schedule 14.08.2013
comment
Удивительно, но это именно то, что было сказано в принятом ответе (и некоторых других) ... за 2 года до вас. - person Chris Baker; 20.09.2014

Установите верхнюю дату на date + 1 день, поэтому в вашем случае установите ее на 2011-02-01.

person Rafal    schedule 22.02.2011
comment
Это будет неправильно включать нулевое время 1 февраля .... Вот почему BETWEEN следует игнорировать; но вместо них следует использовать >= и <. - person Disillusioned; 27.02.2017

Вы можете запустить запрос как:

select * from person where dob between '2011-01-01' and '2011-01-31 23:59:59'

как указывали другие, если ваши даты жестко запрограммированы.

С другой стороны, если дата находится в другой таблице, вы можете добавить день и вычесть секунду (если даты сохранены без секунды / времени), например:

select * from person JOIN some_table ... where dob between some_table.initial_date and (some_table.final_date + INTERVAL 1 DAY - INTERVAL 1 SECOND)

Избегайте выполнения приведений к dob полям (как в принятом ответе), потому что это может вызвать огромные проблемы с производительностью (например, невозможность использовать индекс в поле dob, если он есть). План выполнения может измениться с using index condition на using where, если вы сделаете что-то вроде DATE(dob) или CAST(dob AS DATE), поэтому будьте осторожны!

person Lucas Basquerotto    schedule 04.01.2019

В MySql значения включены, поэтому, когда вы даете, попробуйте попасть между '2011-01-01' и '2011-01-31'

он будет включать от 2011-01-01 00:00:00 до 2011-01-31 00:00:00, поэтому на самом деле ничего в 2011-01-31, так как его время должно идти с 2011-01-31 00:00:00 ~ 2011-01-31 23:59:59

Для верхней границы вы можете изменить на 2011-02-01, тогда будут получены все данные до 2011-01-31 23:59:59.

person haneulkim    schedule 29.10.2019

person    schedule
comment
Ответ Дэниела Хилгарта объясняет проблему, Гуарав предлагает быстрое и простое решение. - person Geoff Kendall; 07.11.2014
comment
Я думаю, что стоит отметить, что это не будет включать даты в 2011-01-31 23:59:59, но будет включать даты до 2011-01-31 23:59:58 последняя секунда дня не включена Это может быть незначительно, но кто-то выиграет от. - person doc_id; 27.05.2015
comment
rahmanisback из документации MySQL. Я могу подтвердить, что последняя секунда БУДЕТ включена, поскольку BETWEEN включает оба направления. см. dev.mysql.com/doc/refman/ 5.5 / ru / - person Felype; 25.11.2015
comment
Да, @Felype, ты прав. Я сам проверил это в базе данных mysql. Он также включает 23:59:59 в результат. Так что оба пути включены. - person Lucky; 29.02.2016
comment
Если столбец dob является меткой времени с точностью до субсекунды, тогда BETWEEN по-прежнему не будет пропускать события в течение последней секунды дня, если вместо этого не используется '2011-02-01 00:00:00'? - person nitrogen; 22.07.2016
comment
-1. Не будет включать 2011-01-31 23:59:59.003. @nitrogen, использующий 2011-02-01 000:00:00, неправильно будет включать нулевое время 1 февраля .... Вот почему вместо этого следует использовать >= и <. - person Disillusioned; 27.02.2017