SELECT, WHERE & ORDER BY
SQL (Structured Query Language) is how we talk to relational databases like MySQL. A database stores data in tables of
rows and columns, and almost every question you will ever ask starts with SELECT.
The examples use an employees(id, name, city, department, salary, joined_on, manager_id) table.
The shape of a query
SELECT name, city, salary
FROM employees
WHERE city = 'Pune' AND salary > 50000
ORDER BY salary DESC
LIMIT 10;
Read it as: take the employees table, keep only rows that pass the WHERE test, show these three columns, sort them,
and return the first ten. Every MySQL statement ends with a semicolon.
Choosing columns
SELECT * FROM employees; -- every column: fine while exploring
SELECT DISTINCT city FROM employees; -- unique cities only
SELECT name AS employee, salary * 12 AS annual_ctc
FROM employees; -- expressions and aliases
Avoid SELECT * in application code: it moves columns you do not need and breaks the day the table changes.
Filtering with WHERE
| Operator | Example |
|---|---|
= , <> |
department = 'Sales' |
> < >= <= |
salary >= 60000 |
BETWEEN |
salary BETWEEN 30000 AND 60000 (inclusive) |
IN |
city IN ('Delhi', 'Pune', 'Kochi') |
LIKE |
name LIKE 'A%' (starts with A), '%kumar%' |
IS NULL |
manager_id IS NULL |
NOT |
city NOT IN ('Delhi') |
Combine tests with AND and OR, and use brackets when you mix them, because AND binds more tightly than OR.
SELECT name, city, salary
FROM employees
WHERE department = 'Sales'
AND (city = 'Mumbai' OR city = 'Surat')
AND joined_on >= '2024-04-01';
Text comparisons are case-insensitive under MySQL 8's default utf8mb4_0900_ai_ci collation, so 'pune' matches 'Pune'.
NULL is not a value
NULL means "unknown", and any comparison with it is unknown too, so salary = NULL never matches. Use IS NULL and
IS NOT NULL, and COALESCE(bonus, 0) to substitute a default.
Sorting and paging
SELECT name, department, salary
FROM employees
ORDER BY department ASC, salary DESC
LIMIT 20 OFFSET 40; -- rows 41-60, i.e. page 3
ORDER BY accepts several columns, an alias, or an expression. Without it, row order is not guaranteed.
The order MySQL really works in
| Step | Clause |
|---|---|
| 1 | FROM |
| 2 | WHERE |
| 3 | GROUP BY |
| 4 | HAVING |
| 5 | SELECT (aliases are created here) |
| 6 | ORDER BY |
| 7 | LIMIT |
That is exactly why an alias defined in SELECT may be used in ORDER BY but not in WHERE.
Common mistakes
- Quoting text with double quotes; MySQL convention is single quotes,
'Pune'. - Writing
= NULLinstead ofIS NULL. - Expecting
BETWEEN '2026-01-01' AND '2026-01-31'to include aDATETIMEat 10:30 on the 31st — it does not. - Leading wildcards such as
LIKE '%sharma', which cannot use an index. - Forgetting
LIMITwhile exploring a million-row table.
Practice
Create an employees table with 20 rows across at least four cities. Write queries that (a) list the five
highest-paid employees outside Delhi, (b) show the distinct departments, (c) find employees whose name contains
"an" and who joined in the last year, and (d) list everyone with no manager.