00:00

MySQL AND with OR Condition

Last updated:

Real filters often mix AND and OR: laptops or phones under ₹30,000. How MySQL groups these operators decides which rows you get, and one missing pair of parentheses is one of the most common bugs in SQL. This tutorial shows exactly how mixed conditions are evaluated.

1. Operator Precedence

PriorityOperator
1 (highest)Comparisons: =, <, >, IN, LIKE, BETWEEN, IS NULL
2NOT
3AND
4XOR
5 (lowest)OR
How parentheses change the meaning of AND and ORLeft tree: without parentheses, AND groups first, so the condition is category = Laptop OR (category = Phone AND price < 30000). Right tree: with parentheses, (category = Laptop OR category = Phone) AND price < 30000.A OR B AND Cmeans A OR (B AND C)ORA: LaptopANDB: PhoneC: < 30000(A OR B) AND Cprice rule applies to bothANDORC: < 30000A: LaptopB: Phone
Figure 1: AND is evaluated before OR, unless parentheses say otherwise.

Table: products (7 rows)

idnamecategorybrandpricein_stockrating
1Zen Laptop 14LaptopZentek5800014.4
2Zen Laptop 13LaptopZentek2400003.9
3Nova PhonePhoneNovo2700014.1
4Nova Phone ProPhoneNovo4800014.6
5Pixel TabTabletPixa2900014.0
6Budget PhonePhoneKiwi900003.6
7Edge LaptopLaptopEdge720001NULL

2. The Classic Mistake

Goal: laptops or phones costing under ₹30,000. Written without parentheses:

query.sql
SELECT name, category, price FROM products
WHERE category = 'Laptop' OR category = 'Phone' AND price < 30000;

Result: 5 rows

namecategoryprice
Zen Laptop 14Laptop58000
Zen Laptop 13Laptop24000
Nova PhonePhone27000
Budget PhonePhone9000
Edge LaptopLaptop72000

Zen Laptop 14 (₹58,000) and Edge Laptop (₹72,000) slipped in, because MySQL read it as Laptop OR (Phone AND < 30000). With parentheses:

query.sql
SELECT name, category, price FROM products
WHERE (category = 'Laptop' OR category = 'Phone') AND price < 30000;

Result: 3 rows

namecategoryprice
Zen Laptop 13Laptop24000
Nova PhonePhone27000
Budget PhonePhone9000
Always add parentheses when a WHERE clause contains both AND and OR, even when the default precedence happens to be what you want. It documents your intent.

3. Evaluating Step by Step

Let's evaluate both versions for the Zen Laptop 14 row (category Laptop, price 58000):

StepWithout parenthesesWith parentheses
ComparisonsTRUE OR FALSE AND FALSE(TRUE OR FALSE) AND FALSE
GroupTRUE OR (FALSE AND FALSE)(TRUE) AND FALSE
ResultTRUE OR FALSE = TRUEFALSE
query.sql
SELECT TRUE OR FALSE AND FALSE AS no_parens, (TRUE OR FALSE) AND FALSE AS with_parens;

Result: 1 row

no_parenswith_parens
10

4. Useful Patterns

Alternatives sharing a common filter:

query.sql
SELECT name, brand, price FROM products
WHERE in_stock = TRUE
  AND (brand = 'Novo' OR brand = 'Pixa');

Result: 3 rows

namebrandprice
Nova PhoneNovo27000
Nova Phone ProNovo48000
Pixel TabPixa29000

Different rules per category (OR of AND-groups):

rules-per-category.sql
SELECT name, category, price, rating
FROM products
WHERE (category = 'Laptop' AND price < 60000 AND rating >= 4)
   OR (category = 'Phone'  AND price < 30000)
   OR (category = 'Tablet' AND in_stock = TRUE);

Result: 4 rows

namecategorypricerating
Zen Laptop 14Laptop580004.4
Nova PhonePhone270004.1
Pixel TabTablet290004.0
Budget PhonePhone90003.6

Simplify repeated ORs on one column with IN:

query.sql
SELECT name FROM products WHERE category IN ('Laptop', 'Phone') AND price < 30000;

Result: 3 rows

name
Zen Laptop 13
Nova Phone
Budget Phone

5. NULLs in Mixed Conditions

Edge Laptop's rating is NULL. In A OR (B AND rating >= 4) the NULL only matters if A is false:

query.sql
SELECT name, rating FROM products WHERE brand = 'Edge' OR (category = 'Laptop' AND rating >= 4);

Result: 2 rows

namerating
Zen Laptop 144.4
Edge LaptopNULL
query.sql
SELECT name, rating FROM products WHERE category = 'Laptop' AND (rating >= 4 OR price > 70000);

Result: 2 rows

namerating
Zen Laptop 144.4
Edge LaptopNULL

Edge Laptop appears in both: the first through brand = 'Edge', the second through price > 70000 (TRUE OR NULL is TRUE).

6. Adding NOT

NOT binds tighter than AND and OR, so it applies only to the condition right after it unless you add parentheses:

query.sql
SELECT name FROM products WHERE NOT category = 'Phone' AND price < 30000;

NOT applies to category only

name
Zen Laptop 13
Pixel Tab
query.sql
SELECT name FROM products WHERE NOT (category = 'Phone' AND price < 30000);

NOT applies to the whole group

name
Zen Laptop 14
Zen Laptop 13
Nova Phone Pro
Pixel Tab
Edge Laptop

7. Writing Readable Conditions

  • Put each AND/OR group on its own line, with the operator at the start of the line.
  • Use parentheses around every OR group.
  • Replace long OR chains on one column with IN.
  • If a WHERE clause grows very large, consider a lookup table or a CASE expression.
  • Test edge cases: boundary prices, NULLs, and rows that should be excluded.

8. Practice Exercises

Exercise 1: In-stock products that are either rated 4.5+ or cost under ₹10,000.
solution.sql
SELECT name, price, rating FROM products
WHERE in_stock = TRUE AND (rating >= 4.5 OR price < 10000);

Result: 1 row

namepricerating
Nova Phone Pro480004.6
Exercise 2: Zentek laptops, or any phone that is out of stock.
solution.sql
SELECT name, brand, in_stock FROM products
WHERE (brand = 'Zentek' AND category = 'Laptop')
   OR (category = 'Phone' AND in_stock = FALSE);

Result: 3 rows

namebrandin_stock
Zen Laptop 14Zentek1
Zen Laptop 13Zentek0
Budget PhoneKiwi0

9. Summary

  • Precedence: comparisons, then NOT, then AND, then OR.
  • A OR B AND C means A OR (B AND C).
  • Always use parentheses when mixing AND and OR.
  • TRUE OR NULL is TRUE and FALSE AND NULL is FALSE; other NULL combinations stay NULL.