Стаття "Між" MySQL не включена?


142

Якщо я запускаю запит із 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 до кінцевої дати, оскільки її вибрали користувачі.)


Ні. Я моє встановлення MySQL (версія?) BETWEENВключно для обох значень. У мене MySQL Server 5.7на Windows 10.
Зелений

Відповіді:


181

Поле, dobймовірно, має компонент часу.

Щоб урізати це:

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

59
Замість CAST(dob AS DATE)вас можна використовувати більш лаконічні DATE(dob).
jkndrkn

11
Хоча це працює, ви отримаєте кращі показники, використовуючи >=та <замість них between.
Девід Харкнесс

112
Ви отримаєте кращі показники, використовуючи dob BETWEEN '2011-01-01 00:00:00' AND '2011-01-31 23:59:59. Це тому, що DATE(dob)має обчислювати значення для кожного рядка і не може використовувати жодні індекси в цьому полі.
Джошуаедлунд

2
@joshuahedlund Будь ласка, додайте відповідь до цього рішення. CAST не настільки ефективний.
doc_id

3
@joshuahedlund Це працює, поки ви не отримаєте дані в рази t > 23:59:59 and t < 24:00:00. Чому BETWEENвзагалі мати справу з погано вказаними ? Швидше слідувати порадам і використовувати Давида: WHERE dob >= '2011-01-01' AND dob < '2011-02-01'. Найкраща ефективність, і вона працює щоразу.
Розчарований

300

З посібника з MySQL :

Це еквівалентно виразу (min <= expr AND expr <= max)


3
Посібник, пов’язаний з цією відповіддю, показує, що перевага віддається перевагу при порівнянні об'єктів DATE та DATETIME. Тож я здогадуюсь, що у @tiagoinu є найповніша відповідь у найсуворішому сенсі, але обидва є на місці.
Кінгсолмн

@jemminger може бути , тому що відповідь від головного конкурента -postgres хлопця: P
Навфал

27
Коротше кажучи, між інклюзивним ... ось чому ця відповідь хитається.
Рафаель

6
Старий коментар, але я хотів прив’язати це до конкретного запиту. "МЕЖДУ" включено, але дати без вказаного часу до 00:00:00. Тому порівняння за діапазоном дат втратить останній день. Або зателефонуйте DATE (dob) або уточніть кінець дня.
wintermute92

вони кажуть, що практика - це золото, з мого випадку використання це зовсім не включено, мені цікаво, чому це відбувається зі мною. Я намагався, а іноді це працює, іноді ні. використовуючи його в полі даних TIME.
Jeffery ThaGintoki

99

Проблема в тому, що 2011-01-31 дійсно є 2011-01-31 00:00:00. Це початок дня. Все протягом дня не входить.


19
Це дійсно пояснює, що відбувається, і відповідає на питання.
Іван П

3
Зрештою, ця відповідь як і раніше найкраща. Дуже дякую.
Страбек

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

1
Я думаю, що варто зауважити, що сюди не будуть входити дати, 2011-01-31 23:59:59але вони включатимуть тих, хто до 2011-01-31 23:59:58 останньої секунди дня не включається. Це може бути незначним, але хтось матиме користь.
doc_id

1
rahmanisback з MySQL Documentation Я можу підтвердити, що остання секунда буде включена, оскільки МЕЖДЕ в обох напрямках. зверніться до dev.mysql.com/doc/refman/5.5/uk/…
Феліпе,

1
Так, @Felype, ти маєш рацію. Я сам це перевірив у базі даних mysql. Він включає також 23:59:59і результат. Тож обидва способи включно.
Пощастило

2
Якщо dobстовпець є часовою позначкою з точністю до другої секунди, то все BETWEENодно не буде пропущено подій протягом останньої секунди дня, якщо замість цього не використовується '2011-02-01 00:00:00'?
азот

1
-1. Не включатимуть 2011-01-31 23:59:59.003. При використанні азоту неправильно2011-02-01 000:00:00 буде включено нульовий час 1 лютого .... Ось чому і його слід використовувати замість цього. >=<
Розчарований

6

Є чи поле ви посилаєтеся в запиті з датою типу або DateTime типу?

Загальна причина поведінки, яку ви описуєте, - це коли ви використовуєте тип DateTime, де ви дійсно повинні використовувати тип дати. Тобто, якщо вам справді не потрібно знати, у який час народився хтось, просто використовуйте тип дати.

Причина, коли останній день не включається до ваших результатів, полягає в тому, що запит передбачає частину часу тих дат, які ви не вказали у своєму запиті.

Тобто: Ваш запит інтерпретується як до півночі між 2011-01-30 та 2011-01-31, однак дані можуть мати значення десь пізніше дня 2011-01-31.

Пропозиція: Змініть поле на тип дати, якщо це тип DateTime.


4

Привіт, цей запит працює для мене,

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

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

Дивно, але такі перетворення - це рішення багатьох проблем у MySQL.


10
Дивно, але саме так сказала прийнята відповідь (та кілька інших) ... 2 роки до того, як ви це зробили.
Кріс Бейкер

0

Встановіть верхню дату на дату + 1 день, тому у вашому випадку встановіть її на 2011-02-01.


1
Це буде неправильно включати нульовий час 1 лютого .... Ось чому BETWEENслід ігнорувати; але >=і їх <слід використовувати замість цього.
Розчарований

0

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

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), тому будьте обережні!


0

У MySql між значеннями включено значення, тому, коли ви намагаєтеся пройти між '2011-01-01' та '2011-01-31'

тому він буде включати з 2011-01-01 00:00:00upto, 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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.