MySQL запрос сравнения дат - PullRequest
0 голосов
/ 28 мая 2019

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

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

Я прочитал следующее Q / A, но я все еще что-то упускаю

Есть подсказка? Спасибо

Ответы [ 3 ]

2 голосов
/ 28 мая 2019

Вы должны заключить свой 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';
2 голосов
/ 28 мая 2019

Ваш запрос имеет форму

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)

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

1 голос
/ 28 мая 2019

Переосмысление в

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';

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...