WHERE, operators, ORDER BY & LIMIT
Comparison and logical operators, IN, BETWEEN, LIKE, NULL checks, sorting and pagination.
SELECT on its own returns every row. WHERE keeps only the rows that match a condition, ORDER BY puts them in order, and LIMIT takes a slice. Together they answer most everyday questions: "the 10 most recent orders over ₹5,000", "customers in Pune who haven't verified their email", and so on.
Sample data#
Comparison operators#
String comparisons follow the column's collation. With MySQL 8's default utf8mb4_0900_ai_ci, they're case-insensitive: WHERE dept = 'sales' matches 'Sales'.
AND, OR, NOT and parentheses#
AND is evaluated before OR, just as multiplication happens before addition. Without the parentheses, this query would mean "all of Sales, plus IT people earning over 60,000". Always add parentheses when you mix AND and OR.
IN and BETWEEN#
IN is shorthand for several ORs on the same column:
BETWEEN a AND b is inclusive at both ends:
Datetime trap: on a
DATETIMEcolumn,BETWEEN '2022-01-01' AND '2022-12-31'stops at midnight on 31 December, missing the rest of that day. Use a half-open range instead:created_at >= '2022-01-01' AND created_at < '2023-01-01'.
Pattern matching with LIKE#
% matches any number of characters (including none) and _ matches exactly one:
To match a literal % or _, escape it: LIKE '100\%'. For richer patterns, MySQL 8 supports regular expressions with REGEXP (or REGEXP_LIKE()):
A pattern with a leading wildcard (LIKE '%ee%') can't use an ordinary index, so it scans the whole table. For searching text at scale, see Full-text search.
Working with NULL#
NULL means unknown. Any comparison with NULL gives NULL (not true), so rows are silently dropped:
Two more NULL surprises:
WHERE city <> 'Pune'does not return Karan, because his city is unknown. WriteWHERE city <> 'Pune' OR city IS NULLif you want him.WHERE id NOT IN (1, 2, NULL)returns no rows at all, since every comparison with theNULLis unknown. Watch for this with subqueries that can returnNULL(see Subqueries).
Sorting with ORDER BY#
ASC(ascending) is the default.DESCreverses the order.- Each column has its own direction. Here, ties on salary (Neha and Rohan) are broken alphabetically.
- You can sort by an alias or an expression, e.g.
ORDER BY YEAR(hired).
NULLs sort first in ascending order and last in descending order. To force them last in an ascending sort, sort on IS NULL first (false = 0 comes before true = 1):
Custom order with FIELD(), which returns the position of a value in a list:
LIMIT, OFFSET and pagination#
"Top N" queries combine ORDER BY and LIMIT. The three most recent hires:
For pages of results, skip rows with OFFSET. Page p (starting at 1) with n rows per page is LIMIT n OFFSET (p - 1) * n:
Two important rules:
- Sort by something unique. If several rows tie on the sort key, rows can jump between pages. Add the primary key as a tie-breaker:
ORDER BY salary DESC, id. - Large offsets are slow.
OFFSET 100000still reads and throws away 100,000 rows. For deep pagination use keyset pagination ("seek method"): remember the last row you showed and continue after it:
With an index on the sort column, this is fast no matter how deep you go.
Putting it together#
Engineers or IT staff in Pune or Bengaluru hired since 2020, best paid first:
Common mistakes#
= NULLinstead ofIS NULL.- Forgetting parentheses around
ORconditions. - Using
BETWEENwith datetimes and missing the last day. LIMITwithoutORDER BY, which gives unpredictable "top" rows.- Wrapping an indexed column in a function, as in
WHERE YEAR(hired) = 2021. It works, but it stops MySQL using an index onhired. Preferhired >= '2021-01-01' AND hired < '2022-01-01'(more in Indexes).
What's next#
Next you'll transform values with MySQL's built-in string, numeric and control-flow functions.
Check your understanding
Quick quiz
1.Which WHERE clause correctly finds employees whose manager is unknown?
2.What does
ORDER BY salary DESC, namedo?3.
WHERE dept = 'Sales' OR dept = 'IT' AND salary > 60000is evaluated as…
Finished reading?
Mark this lesson complete to track your progress.