SQL AND, OR and NOT Operators
A single condition is rarely enough. “Furniture and under 5,000″, “Pune or Delhi”, “not cancelled”: AND, OR and NOT combine conditions in a WHERE clause. The one rule that catches everyone is precedence: AND binds tighter than OR, so you need parentheses more often than you think.
- Require several conditions with
AND - Accept any of several conditions with
OR - Negate a condition with
NOT - Use parentheses to control precedence, and know how NULL affects logic
Sample data
| product_id | product_name | category | price | stock |
|---|---|---|---|---|
| 1 | Wireless Mouse | Electronics | 799 | 120 |
| 2 | Mechanical Keyboard | Electronics | 3499 | 45 |
| 3 | USB-C Hub | Electronics | 1999 | 0 |
| 4 | Office Chair | Furniture | 8999 | 12 |
| 5 | Standing Desk | Furniture | 18999 | 5 |
| 6 | Notebook Pack | Stationery | 249 | 300 |
| 7 | Gel Pens | Stationery | 199 | 250 |
| 8 | Desk Lamp | Furniture | 1499 | 30 |
| 9 | Monitor Arm | Furniture | 2799 | 18 |
AND: every condition must be true
Furniture that costs less than 5,000:
SELECT product_name, category, priceFROM productsWHERE category = 'Furniture' AND price < 5000;| product_name | category | price |
|---|---|---|
| Desk Lamp | Furniture | 1499 |
| Monitor Arm | Furniture | 2799 |
- MySQL checks both conditions for each of the 9 products.
- A row is kept only when both are true: it is Furniture and its price is below 5,000.
- The Office Chair and Standing Desk are Furniture but too expensive, so only the Desk Lamp and Monitor Arm remain.
OR: at least one condition must be true
Employees based in Pune or Delhi:
SELECT first_name, cityFROM employeesWHERE city = 'Pune' OR city = 'Delhi';| first_name | city |
|---|---|
| Priya | Pune |
| Kavya | Pune |
| Rohan | Pune |
| Sneha | Delhi |
- A row is kept when the city is Pune, or Delhi, or (impossible here) both.
- Three employees are in Pune and one in Delhi: 4 rows.
A list of ORs on the same column is easier to read with IN: WHERE city IN ('Pune', 'Delhi').
NOT: reverse a condition
All orders except the delivered ones:
SELECT order_id, statusFROM ordersWHERE NOT status = 'Delivered';| order_id | status |
|---|---|
| 1004 | Cancelled |
| 1006 | Shipped |
| 1008 | Pending |
NOT also combines with other operators: NOT IN, NOT BETWEEN, NOT LIKE, IS NOT NULL.
Precedence: AND before OR
Goal: Electronics or Stationery products that are in stock. This first attempt looks right but is wrong:
SELECT product_name, category, stockFROM productsWHERE category = 'Electronics' OR category = 'Stationery' AND stock > 0;| product_name | category | stock |
|---|---|---|
| Wireless Mouse | Electronics | 120 |
| Mechanical Keyboard | Electronics | 45 |
| USB-C Hub | Electronics | 0 |
| Notebook Pack | Stationery | 300 |
| Gel Pens | Stationery | 250 |
ANDis evaluated beforeOR, so MySQL reads the condition ascategory = 'Electronics' OR (category = 'Stationery' AND stock > 0).- Every Electronics product passes, whatever its stock, so the out-of-stock USB-C Hub (stock 0) slips in.
Parentheses say what you mean:
SELECT product_name, category, stockFROM productsWHERE (category = 'Electronics' OR category = 'Stationery') AND stock > 0;| product_name | category | stock |
|---|---|---|
| Wireless Mouse | Electronics | 120 |
| Mechanical Keyboard | Electronics | 45 |
| Notebook Pack | Stationery | 300 |
| Gel Pens | Stationery | 250 |
- The parentheses group the two category tests into one condition.
- That group and
stock > 0must both be true. - The USB-C Hub now fails the stock test: 4 rows instead of 5.
Whenever a WHERE clause mixes AND and OR, add parentheses, even when the default order happens to be correct. The next person to read the query will thank you.
| Order | Operator |
|---|---|
| 1 | comparisons: =, <, >, LIKE, IN … |
| 2 | NOT |
| 3 | AND |
| 4 | OR |
AND, OR and NULL
SQL uses three-valued logic: a condition can be TRUE, FALSE or UNKNOWN (when NULL is involved). WHERE keeps only TRUE rows.
SELECT first_name, commissionFROM employeesWHERE commission > 5000 OR commission < 5000;| first_name | commission |
|---|---|
| Vikram | 12000 |
| Neha | 6000 |
| Arjun | 4500 |
- For the three sales staff,
commissionhas a value, so one of the two comparisons is true: Vikram (12,000), Neha (6,000), Arjun (4,500). - For the other nine employees
commissionis NULL.NULL > 5000is UNKNOWN, and so isNULL < 5000. - UNKNOWN OR UNKNOWN is still UNKNOWN, so those rows are dropped.
| A | B | A AND B | A OR B |
|---|---|---|---|
| TRUE | UNKNOWN | UNKNOWN | TRUE |
| FALSE | UNKNOWN | FALSE | UNKNOWN |
| UNKNOWN | UNKNOWN | UNKNOWN | UNKNOWN |
A realistic filter
Engineering or Sales employees hired before 2022 who earn at least 90,000:
SELECT first_name, dept_id, hire_date, salaryFROM employeesWHERE (dept_id = 1 OR dept_id = 2) AND hire_date < '2022-01-01' AND salary >= 90000ORDER BY salary DESC;| first_name | dept_id | hire_date | salary |
|---|---|---|---|
| Asha | 1 | 2018-04-12 | 125000 |
| Vikram | 2 | 2017-11-20 | 105000 |
| Rahul | 1 | 2019-07-01 | 98000 |
- The parentheses keep departments 1 and 2.
hire_date < '2022-01-01'removes recent hires.salary >= 90000removes the lower salaries.- Asha, Vikram and Rahul pass all three tests.
Exercise: Cheap or plentiful
List products that cost less than 500 or have more than 100 in stock. Show product_name, price and stock.
| product_name | price | stock |
|---|---|---|
| Wireless Mouse | 799 | 120 |
| Notebook Pack | 249 | 300 |
| Gel Pens | 199 | 250 |
Hint 1
Two conditions joined by OR.
SELECT product_name, price, stockFROM productsWHERE price < 500 OR stock > 100;| product_name | price | stock |
|---|---|---|
| Wireless Mouse | 799 | 120 |
| Notebook Pack | 249 | 300 |
| Gel Pens | 199 | 250 |
Exercise: Delivered in the first quarter
List delivered orders placed in January, February or March 2025 (order_date from 2025-01-01 to 2025-03-31).
| order_id | order_date | status |
|---|---|---|
| 1001 | 2025-01-05 | Delivered |
| 1002 | 2025-01-17 | Delivered |
| 1003 | 2025-02-02 | Delivered |
| 1005 | 2025-03-08 | Delivered |
Hint 1
Three conditions: the status, the first date and the last date, joined with AND.
SELECT order_id, order_date, statusFROM ordersWHERE status = 'Delivered' AND order_date >= '2025-01-01' AND order_date <= '2025-03-31';| order_id | order_date | status |
|---|---|---|
| 1001 | 2025-01-05 | Delivered |
| 1002 | 2025-01-17 | Delivered |
| 1003 | 2025-02-02 | Delivered |
| 1005 | 2025-03-08 | Delivered |
Quick quiz
1. Which is evaluated first?
AND has higher precedence than OR.
2. WHERE a = 1 OR b = 2 AND c = 3 is the same as…
AND binds tighter, so it groups b = 2 AND c = 3.
3. What is TRUE OR UNKNOWN?
If one side of OR is true, the whole expression is true.
4. Why does WHERE commission > 5000 OR commission < 5000 skip employees with a NULL commission?
Any comparison with NULL is UNKNOWN, and WHERE keeps only TRUE.
AND / OR FAQ
What is the difference between AND and OR in SQL?
AND returns a row only when all conditions are true. OR returns a row when at least one condition is true.
Does AND or OR come first in SQL?
AND is evaluated before OR. Use parentheses to change the order or simply to make it obvious.
Can I use AND and OR in the same WHERE clause?
Yes, as long as you group conditions with parentheses, for example WHERE (city = 'Pune' OR city = 'Delhi') AND salary > 50000.
How does NOT work with NULL?
NOT UNKNOWN is still UNKNOWN, so NOT (commission > 5000) does not return rows where commission is NULL. Test for NULL explicitly with IS NULL.