1

SETUP:

MySQL 5.7.14 (Google SQL)

DESCRIPTION:

In the following scenario it appears I am getting some false matches in my where clause where I'm NOT using parentheses. But adding the parentheses DOES yield the correct results.

This Query DOES return results with tsd.StatusID = 3 (wrong):

SELECT 
tsee.ID, tsd.StatusID

FROM TSShiftDetails tsd
JOIN TSShiftEmployees tse
    ON tse.ShiftID = tsd.ID
JOIN TSShiftEmpEntries tsee
    ON tsee.ShiftEmpID = tse.ID

WHERE tsee.CCID IN (4590) OR tsee.CCID LIKE null
AND tsd.StatusID != 3

While this query DOES NOT return results with AND tsd.StatusID = 3 (correct):

SELECT 
tsee.ID, tsd.StatusID

FROM TSShiftDetails tsd
JOIN TSShiftEmployees tse
    ON tse.ShiftID = tsd.ID
JOIN TSShiftEmpEntries tsee
    ON tsee.ShiftEmpID = tse.ID

WHERE (tsee.CCID IN (4590) OR tsee.CCID LIKE null)
AND tsd.StatusID != 3

QUESTION:

While I feel I completely understand why the query WITH the parentheses is working. My question is WHY is the one without parentheses returning records with a StatusID == 3? I would think without any functional ordering of parentheses, the AND tsd.StatusID != 3 clause would be applied to every match regardless of the preceding OR.

What Ya'll think? Am I misunderstanding, or is MySQL behaving inconsistently here?

P.S.

FYI, Yes there is a front end application reason for the need to have the Where clause formatted this way. eg. tsee.CCID IN (4590) as opposed to tsee.CCID =4590

Bill Karwin
  • 538,548
  • 86
  • 673
  • 828
DarbyM
  • 1,173
  • 2
  • 9
  • 25

1 Answers1

1

The explanation has nothing to do with LIKE NULL or IN ( ).

Boolean expressions follow an order of operator precedence, just like arithmetic.

In arithmetic, you may remember that multiplication has higher precedence than addition:

A + B * C

Without parentheses, this works exactly like:

A + (B * C)

If you want the addition to be evaluated first, you must use parentheses to override the default operator precedence:

(A + B) * C

Similarly, in boolean expressions, AND has higher precedence than OR.

A OR B AND C

Works like:

A OR (B AND C)

If you want the OR to be evaluated first, you must use parentheses to override the default operator precedence:

(A OR B) AND C

How does this explain what you're seeing?

WHERE tsee.CCID IN (4590) OR tsee.CCID LIKE null
AND tsd.StatusID != 3

This works as if you had done:

WHERE tsee.CCID IN (4590) OR (tsee.CCID LIKE null
AND tsd.StatusID != 3)

So if it finds a row with CCID 4590, that row satisfies the whole WHERE clause, because true OR (anything) is still true.

Bill Karwin
  • 538,548
  • 86
  • 673
  • 828
  • "The explanation has nothing to do with LIKE NULL or IN ( )." 100% correct. I was trying to avoid people focusing on that part of the query. – DarbyM Mar 25 '20 at 15:29
  • Very good explanation. I thought with the absence of parentheses, there was ZERO precedence, and each evaluation was handled individually.... Meaning each evaluation was handled in order, and independent of previous evaluations. Meaning even though the clause matched the 'IN (4590), Failed 'Like' NULL. It would still have to pass the 'AND tsd.StatusID != 3' clause seperately. – DarbyM Mar 25 '20 at 15:35
  • All programming languages that I know of have operator precedence, including SQL. https://dev.mysql.com/doc/refman/8.0/en/operator-precedence.html – Bill Karwin Mar 25 '20 at 16:20