Lesson 3 of 12

SQL WHERE

So far every query has returned all the rows in a table. Real questions are more specific: which customers are in Tamil Nadu? Which products cost more than ₹200? The SQL WHERE clause answers them by keeping only the rows that match a condition. It builds directly on SQL SELECT.

How SQL WHERE works

WHERE comes after FROM. The database checks the condition against each row, one at a time. If the condition is true, the row goes into the result; if it is false (or unknown, as you will see with NULL), the row is skipped.

SELECT CustomerName, City
FROM Customers
WHERE State = 'Tamil Nadu';

Returns 3 rows: Annapoorna Stores (Chennai), Coimbatore Mart (Coimbatore) and Jasmine Mini Mart (Madurai).

The text value 'Tamil Nadu' is in single quotes. Numbers are written without quotes.

Comparison operators

OperatorMeaningExample
=Equal toStatus = 'Delivered'
<> or !=Not equal toCountry <> 'India'
>Greater thanSalary > 60000
<Less thanPrice < 100
>=Greater than or equal toPrice >= 200
<=Less than or equal toQuantity <= 5

<> is the standard SQL way to say “not equal”. != works in SQLite, MySQL and SQL Server too, so use whichever you find easier to read – just stay consistent.

SELECT ProductName, Price
FROM Products
WHERE Price >= 200;

Returns 5 rows: Filter Coffee Powder, Cow Ghee, Ponni Rice, Wheat Atta and Cardamom.

Comparing text and dates

In SQLite, = on text is case-sensitive: City = 'chennai' finds nothing, because the stored value is 'Chennai'. MySQL behaves differently – its default collations ignore case, so the same query would match. If you need case-insensitive matching in SQLite, compare LOWER(City) = 'chennai', or use LIKE, which you will meet in SQL LIKE and Wildcards.

SQLite has no separate date type. Our sample database stores dates as text in the YYYY-MM-DD format. Because the year comes first, ordinary text comparison puts dates in the right order, so OrderDate >= '2026-03-01' works as expected. MySQL has a real DATE type, but it accepts the same 'YYYY-MM-DD' style, so the query looks the same.

Combining conditions with AND, OR and NOT

  • AND – both conditions must be true.
  • OR – at least one condition must be true.
  • NOT – reverses a condition, e.g. NOT Status = 'Cancelled'.

You can chain as many conditions as you need. Each extra AND makes the result smaller, because a row has to pass every test. Each extra OR makes it larger, because a row only has to pass one. Keeping this picture in mind helps when a query returns far more or far fewer rows than you expected.

SELECT OrderID, OrderDate, Status
FROM Orders
WHERE OrderDate >= '2026-03-01'
  AND Status <> 'Delivered';

Returns 3 rows: order 1007 (Shipped), 1009 (Pending) and 1010 (Shipped).

Use brackets when you mix AND and OR

AND is evaluated before OR, just as multiplication comes before addition in maths. This often catches beginners. Suppose you want developers or sales staff who earn more than ₹70,000. Run the query below, then remove the brackets and run it again.

SELECT FirstName, Department, Salary
FROM Employees
WHERE (Department = 'Development' OR Department = 'Sales')
  AND Salary > 70000;

Returns 2 rows: Rahul (85000) and Nisha (78000). Without the brackets you get 3 rows, because Ajay (62000) slips in.

Without brackets the database reads it as Development OR (Sales AND salary above 70,000), so every developer appears whatever their salary. When a condition mixes AND and OR, always add brackets – even when they are not strictly needed, they make your intention clear.

Missing values: IS NULL

NULL means “no value” or “unknown”. In our data, two overseas customers have no state. NULL is not zero and not an empty string, and it cannot be compared with =. Even NULL = NULL is not true; it is unknown. So WHERE State = NULL always returns no rows. Use IS NULL and IS NOT NULL instead:

SELECT CustomerName, City, Country
FROM Customers
WHERE State IS NULL;

Returns 2 rows: Indus Grocers (Dubai, UAE) and Lotus Organics (Singapore).

Watch out: A condition such as State <> 'Kerala' also skips rows where State is NULL, because comparing with an unknown value gives an unknown answer. If you want those rows too, add OR State IS NULL.

WHERE beyond SELECT

The same SQL WHERE clause is used with UPDATE and DELETE to choose which rows to change – you will see this in SQL INSERT, UPDATE and DELETE. Getting comfortable with conditions now will save you from changing the wrong rows later. Next up: sorting the result in SQL ORDER BY and LIMIT.

Further reading

Key takeaways

  • WHERE keeps only the rows for which the condition is true.
  • Use =, (or !=), , = to compare values; put text and dates in single quotes.
  • AND is evaluated before OR, so add brackets when you mix them.
  • NULL means unknown: test it with IS NULL or IS NOT NULL, never with =.
  • Text comparison with = is case-sensitive in SQLite but usually not in MySQL.

Quick quiz

Check what you learned – pick an answer.

1. Which query finds customers whose PostalCode is missing?

2. What does WHERE Department = 'Sales' OR Department = 'Design' AND Salary > 70000 return?

3. In SQLite, does WHERE City = 'mumbai' match a row where City is 'Mumbai'?

Practice exercise

List the name and price of every product in category 2 (Snacks) that costs less than ₹100.

Show a hint

Combine two conditions with AND.

Show the solution
SELECT ProductName, Price
FROM Products
WHERE CategoryID = 2
  AND Price < 100;

Progress is saved in this browser only.