Reputation: 1721
I have this table in my database:
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 is type DATE
I would like to select the rows where a = 81 or b = 81 and date_x is before 2019-05-28 .
So I perform the following query in MySQL Workbench:
SELECT * FROM t
WHERE a = '81' OR b = '81'
AND date_x > '2019-05-28';
This is what I get:
1 | 81 | 12 | 2018-03-16
3 | 81 | 67 | 2018-03-16
I would expect that 2018-03-16 is not later than 2019-05-28 . Moreover, why only 2 rows returned? There is another with same date in date_x column.
This query return the same:
SELECT * FROM t
WHERE a = '81' OR b = '81'
AND date_x > str_to_date('2019-05-28', '%Y-$m-%d');
I have performed the following query for debug:
SELECT * FROM t
WHERE a = '81' OR b = '81'
AND date_x < '2019-05-28';
and
SELECT * FROM t
WHERE a = '81' OR b = '81'
AND date_x < str_to_date('2019-05-28', '%Y-$m-%d');
then both return, as expected:
1 | 81 | 12 | 2018-03-16
3 | 81 | 67 | 2018-03-16
4 | 763 | 81 | 2018-03-16
I read the following Q/A but I'm still missing something:
Any hint? Thank you
Upvotes: 1
Views: 79
Reputation: 11602
A rewite into
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'
might make more sense especially when you consider performance, consider this table structure and indexing..
CREATE TABLE t (
`id` INTEGER,
`a` INTEGER,
`b` INTEGER,
`date_x` VARCHAR(10)
, INDEX(a, date_x)
, INDEX(b, date_x)
);
As
SELECT * FROM t
WHERE (a = '81' OR b = '81')
AND date_x > '2019-05-28';
can't use indexes see demo and most likely ends up scanning the complete table/index files.
As the MySQL optimizer is costs based i also included this to make sure the FULL scan for the first query was not simply triggerd by a to low number off records..
But it's but clear the second query has the more stabile plan..
Oracle database i believe does to OR
to UNION ALL
rewite direcly in this optimizer if indexed. As MySQL is owned by Oracle i hope they also add it that optimizion in MySQL.
Upvotes: 1
Reputation: 2195
You should wrap your select
in brackets. Because of it you get 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';
Upvotes: 2
Reputation: 1545
Your query has the form
SELECT * FROM t WHERE condition_a OR condition_b AND condition_c
The AND
operator binds more strongly than OR
, therefore you end up with
SELECT * FROM t WHERE condition_a OR (condition_b AND condition_c)
This is where I think the confusion comes from. Nothing to do with dates as such.
Upvotes: 2