Full clause order
SELECT [DISTINCT] columns
FROM table
[JOIN other_table ON condition]
[WHERE row_filter]
[GROUP BY columns]
[HAVING group_filter]
[ORDER BY columns [ASC|DESC]]
[LIMIT n OFFSET m];
Logical execution order
MySQL does not run the clauses top to bottom. It evaluates them like this:
FROM → JOIN → WHERE → GROUP BY → HAVING → SELECT → DISTINCT → ORDER BY → LIMIT
This explains two common surprises: you cannot use a SELECT alias inside WHERE (the alias does not exist yet), but you can use it in ORDER BY and HAVING.
Examples
SELECT * FROM students; -- everything (avoid in production code)
SELECT name_en, cgpa FROM students; -- specific columns
SELECT DISTINCT department FROM students; -- unique values
Aliases
SELECT
name_en AS student_name,
cgpa * 25 AS percentage,
department dept -- AS is optional
FROM students AS s;
Use backticks when a name has spaces or is a reserved word: SELECT name_en AS `Full Name`.
Expressions and constants
SELECT 5 + 3, NOW(), DATABASE(), USER(), VERSION();
SELECT
name_en,
CONCAT(name_en, ' (', department, ')') AS label,
ROUND(cgpa * 25, 1) AS pct
FROM students;
Limiting output
SELECT * FROM students LIMIT 5; -- first 5
SELECT * FROM students LIMIT 10 OFFSET 20; -- rows 21-30 (pagination)
SELECT * FROM students LIMIT 20, 10; -- same, older syntax
LIMITwithoutORDER BYgives no guaranteed order. Always pair them when paginating.
Good habits
- Select only the columns you need —
SELECT *transfers data you throw away and blocks covering-index optimisations. - End every statement with a semicolon.
- Uppercase keywords, lowercase identifiers: it makes long queries readable.