SQL Cheatsheet
A quick reference for SQL syntax: clause execution order, joins, filtering, aggregates, and where MySQL, PostgreSQL, SQLite, and T-SQL disagree.
A quick reference for SQL query syntax: clause order, joins, common functions, and where MySQL, PostgreSQL, SQLite, and T-SQL disagree. Paste any query into the SQL Formatter to have it beautified for the dialect you pick.
Clause order: written vs executed
SQL is written in one order but evaluated in a different one — this is the single most common source of confusion for anyone new to the language, including why a column alias defined in SELECT cannot be used in that same query's WHERE clause.
| Written order | Logical execution order |
|---|---|
1. SELECT | 4. SELECT |
2. FROM | 1. FROM |
3. WHERE | 2. WHERE |
4. GROUP BY | 3. GROUP BY / HAVING |
5. HAVING | 5. ORDER BY |
6. ORDER BY | 6. LIMIT / OFFSET |
7. LIMIT | — |
Because FROM and WHERE run before SELECT even exists, a WHERE clause cannot reference a column alias created in SELECT — that alias does not exist yet at the point WHERE is evaluated. ORDER BY, which runs last, can reference SELECT aliases without issue.
Joins
| Join | Returns |
|---|---|
INNER JOIN | Only rows with a match in both tables |
LEFT JOIN | All rows from the left table, matched rows from the right, NULL where no match |
RIGHT JOIN | All rows from the right table, matched rows from the left, NULL where no match |
FULL OUTER JOIN | All rows from both tables, NULL on whichever side has no match |
CROSS JOIN | Every row from the left paired with every row from the right (cartesian product) |
SQLite and MySQL (before 8.0.14) do not support FULL OUTER JOIN directly — it is commonly emulated with a LEFT JOIN and a RIGHT JOIN combined with UNION.
Filtering
| Operator | Meaning |
|---|---|
=, <> / != | Equal, not equal |
BETWEEN a AND b | Inclusive range |
IN (a, b, c) | Matches any value in the list |
LIKE '%abc%' | Pattern match — % any sequence, _ any single character |
IS NULL / IS NOT NULL | NULL check — never use = NULL, it never matches |
NULL is not a value that can be compared with =: it represents "unknown," and any comparison against unknown is itself unknown, not true. WHERE col = NULL silently matches zero rows instead of raising an error.
Aggregates and GROUP BY
| Function | Returns |
|---|---|
COUNT(*) | Number of rows |
SUM(col) | Sum of a numeric column |
AVG(col) | Average of a numeric column |
MIN(col) / MAX(col) | Smallest / largest value |
Every non-aggregated column in SELECT must appear in GROUP BY. Filter on an aggregate with HAVING, not WHERE — WHERE runs before grouping happens, so it cannot see the aggregated result yet.
Dialect differences
| Feature | MySQL | PostgreSQL | SQLite | T-SQL |
|---|---|---|---|---|
| Limit rows | LIMIT n | LIMIT n | LIMIT n | TOP n |
| Quote identifiers | `name` | "name" | "name" | [name] |
| String concat | CONCAT(a,b) | a || b | a || b | a + b |
| Auto-increment PK | AUTO_INCREMENT | SERIAL / GENERATED ALWAYS AS IDENTITY | AUTOINCREMENT | IDENTITY(1,1) |
Standard SQL (ISO/ANSI) uses FETCH FIRST n ROWS ONLY for row limiting, which LIMIT and TOP both predate as vendor extensions — PostgreSQL and modern SQL Server both support the standard form too, alongside their own.
Try it now
Frequently asked questions
SQL is written SELECT-first but executed FROM-first: FROM and WHERE both run before SELECT creates any aliases, so the alias does not exist yet at the point WHERE is evaluated.
ORDER BY runs last, after SELECT, which is why it can reference SELECT aliases without any issue.