Запрос сравнения дат MySQL

У меня есть эта таблица в моей базе данных:

table t

id   |  a   | b  | date_x

1    |  81  | 12 | 2018-03-16
2    |  9   | 54 | 2025-04-21
3    |  81  | 67 | 2018-03-16
4    |  763 | 81 | 2018-03-16
5    |  90  | 22 | 2025-12-08

date_x имеет тип DATE

Я хотел бы выбрать строки, где a = 81 или b = 81, а date_x до 2019-05-28.

Поэтому я выполняю следующий запрос в MySQL Workbench:

SELECT * FROM t
WHERE a = '81' OR b = '81'
AND date_x > '2019-05-28';

Вот что я получаю:

1    |  81  | 12 | 2018-03-16
3    |  81  | 67 | 2018-03-16

Я ожидаю, что 2018-03-16 не позднее 2019-05-28 . Более того, почему вернулось только 2 строки? В столбце date_x есть еще один с той же датой.

Этот запрос возвращает то же самое:

SELECT * FROM t
WHERE a = '81' OR b = '81'
AND date_x > str_to_date('2019-05-28', '%Y-$m-%d');

Я выполнил следующий запрос для отладки:

SELECT * FROM t
WHERE a = '81' OR b = '81'
AND date_x < '2019-05-28';

а также

SELECT * FROM t
WHERE a = '81' OR b = '81'
AND date_x < str_to_date('2019-05-28', '%Y-$m-%d');

то оба возвращаются, как и ожидалось:

1    |  81  | 12 | 2018-03-16
3    |  81  | 67 | 2018-03-16
4    |  763 | 81 | 2018-03-16

Я прочитал следующий вопрос/ответ, но мне все еще чего-то не хватает:

Любой намек? Спасибо

Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
1
0
66
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Ваш запрос имеет вид

SELECT * FROM t WHERE condition_a OR condition_b AND condition_c

Оператор AND связывает сильнее, чем OR, поэтому в итоге вы получите

SELECT * FROM t WHERE condition_a OR (condition_b AND condition_c)

Отсюда я думаю и путаница. Ничего общего с датами как таковыми.

Это на пределе очевидности. Спасибо за помощь в фокусировке в нужную точку

GabrieleMartini 28.05.2019 14:43

Вы должны заключить select в скобки. Благодаря этому вы получаете WHERE a = '81' OR (b = '81' AND date_x >'2019-05-28').

SELECT * FROM t
WHERE (a = '81' OR b = '81')
AND date_x > '2019-05-28';

Это на пределе очевидности. Спасибо за помощь в фокусировке в нужную точку

GabrieleMartini 28.05.2019 14:43

Переписать в

SELECT * FROM t
WHERE a = '81' AND date_x > '2019-05-28'
UNION ALL 
SELECT * FROM t
WHERE b = '81' AND date_x > '2019-05-28'

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

CREATE TABLE t (
  `id` INTEGER,
  `a` INTEGER,
  `b` INTEGER,
  `date_x` VARCHAR(10)
  , INDEX(a, date_x)
  , INDEX(b, date_x)
);

Так как

SELECT * FROM t
WHERE (a = '81' OR b = '81')
AND date_x > '2019-05-28';

не может использовать индексы, см. демо и, скорее всего, в конечном итоге сканирует полные файлы таблиц/индексов.

Поскольку оптимизатор MySQL основан на затратах, я также включил это, чтобы убедиться, что ПОЛНОЕ сканирование для первого запроса не было просто вызвано слишком малым количеством записей..
Но ясно, что второй запрос имеет более стабильный план.

База данных Oracle, я считаю, делает OR для UNION ALL перезаписи непосредственно в этом оптимизаторе, если она проиндексирована. Поскольку MySQL принадлежит Oracle, я надеюсь, что они также добавят эту оптимизацию в MySQL.

Другие вопросы по теме