Skip to content

SQL Syntax Cheat Sheet: Joins, Clauses, and Common Functions

A quick-reference SQL syntax cheat sheet — clause write order vs execution order, join types, aggregate/string/date functions, and CRUD skeletons.

Try it now: SQL Formatter Format and beautify SQL for PostgreSQL, MySQL and SQL Server — clauses on their own lines, subqueries indented, literals untouched.

Clause Order: Written vs. Executed

The single most useful fact on this sql cheat sheet: the order you write clauses in is not the order the database actually runs them in. That mismatch is exactly why WHEREcan't reference a SELECT alias but ORDER BY can — by the time ORDER BY runs, the alias already exists; by the time WHEREruns, it doesn't.

Written orderLogical execution order
1. SELECT1. FROM / JOIN
2. FROM2. WHERE
3. WHERE3. GROUP BY
4. GROUP BY4. HAVING
5. HAVING5. SELECT
6. ORDER BY6. ORDER BY
7. LIMIT7. LIMIT

Same reasoning explains why HAVING filters on aggregates and WHEREcan't —WHERE runs before GROUP BY has produced any aggregates to filter on. Full clause precision and dialect-specific edge cases are covered in the SQL Formatter guide.

Join Types

JoinReturnsExample
INNER JOINOnly rows with a match on both sidesFROM orders o INNER JOIN customers c ON c.id = o.customer_id
LEFT JOINAll rows from the left table; unmatched right-side columns are NULLFROM customers c LEFT JOIN orders o ON o.customer_id = c.id
RIGHT JOINAll rows from the right table; unmatched left-side columns are NULLFROM orders o RIGHT JOIN customers c ON c.id = o.customer_id
FULL OUTER JOINAll rows from both sides; unmatched columns on either side are NULLFROM a FULL OUTER JOIN b ON a.id = b.a_id
CROSS JOINEvery row from the left paired with every row from the right — no ON clauseFROM sizes CROSS JOIN colors

A LEFT JOIN silently turns into an INNER JOIN the moment a WHERE clause filters on a nullable right-side column — a bug common enough to have its own section in the EXPLAIN ANALYZE guide.

Aggregate Functions

FunctionDescriptionExample
COUNT(*)Number of rows in the groupSELECT COUNT(*) FROM orders
SUM(col)Total of a numeric columnSELECT SUM(total) FROM orders
AVG(col)Mean of a numeric columnSELECT AVG(total) FROM orders
MIN(col)Smallest valueSELECT MIN(created_at) FROM orders
MAX(col)Largest valueSELECT MAX(created_at) FROM orders

All five ignore NULL values except COUNT(*), which counts rows regardless of nulls — COUNT(col) counts only the non-null values of that column.

String Functions

FunctionDescriptionExample
CONCAT(a, b)Join strings togetherCONCAT(first_name, ' ', last_name)
UPPER(s) / LOWER(s)Change caseUPPER(email)
TRIM(s)Strip leading/trailing whitespaceTRIM(username)
SUBSTRING(s, start, len)Extract part of a stringSUBSTRING(sku, 1, 3)
LENGTH(s)Character countLENGTH(description)

These names are not universal — this is the sql functions list most engines agree on closely enough to be useful, not a guarantee. Postgres also accepts || for concatenation alongside CONCAT(); SQL Server uses LEN() instead of LENGTH(); MySQL's CONCAT() tolerates NULL arguments where Postgres's || propagates them. Check your specific engine before assuming a name works everywhere.

Date Functions

Function (Postgres)MySQL equivalentSQL Server equivalent
NOW()NOW()GETDATE()
CURRENT_DATECURDATE()CAST(GETDATE() AS DATE)
date_col + interval '1 day'DATE_ADD(date_col, INTERVAL 1 DAY)DATEADD(day, 1, date_col)
date_part('year', date_col)YEAR(date_col)YEAR(date_col)

Date functions vary more across engines than almost anything else in SQL — treat this table as a starting point for translating a query between dialects, not as syntax you can paste unchanged into any database.

CRUD Statement Skeletons

SELECT
SELECT column1, column2
FROM table_name
WHERE condition
GROUP BY column1
HAVING aggregate_condition
ORDER BY column1
LIMIT 10;
INSERT
INSERT INTO table_name (column1, column2)
VALUES (value1, value2);
UPDATE
UPDATE table_name
SET column1 = value1
WHERE condition;
DELETE
DELETE FROM table_name
WHERE condition;

An UPDATE or DELETE with no WHERE clause runs against every row in the table — worth a second look before you hit execute. Building these safely, with real placeholders instead of string-concatenated values, is what the parameterized query builder guide covers.

Formatting the Query You Just Wrote

Writing correct SQL and writing SQL a reviewer can read in a pull request are two different jobs. Once a query works, running it through GenKitLab's SQL Formatter puts each clause on its own line and indents subqueries consistently for Postgres, MySQL or SQL Server — the same before/after transform covered in the SQL Formatter guide. It runs entirely in your browser, so nothing you paste is uploaded anywhere.

Frequently asked questions

What is the correct order of SQL clauses?

Written order is SELECT, FROM, WHERE, GROUP BY, HAVING, ORDER BY, LIMIT. Logical execution order is different: FROM/JOIN, WHERE, GROUP BY, HAVING, SELECT, ORDER BY, LIMIT. The mismatch between the two is why a WHERE clause can't reference a column alias defined in SELECT, but ORDER BY can.

What's the difference between INNER JOIN and LEFT JOIN?

INNER JOIN returns only rows that have a match on both sides. LEFT JOIN returns every row from the left table regardless of a match, filling unmatched right-side columns with NULL — which is also why a WHERE clause that filters on one of those nullable columns can accidentally turn a LEFT JOIN back into an INNER JOIN.

Why can't I use a SELECT alias in a WHERE clause?

Because of execution order, not written order: WHERE runs before SELECT does, so the alias doesn't exist yet when WHERE is evaluated. ORDER BY runs after SELECT, which is why the same alias works fine there.

Are SQL string and date functions the same across Postgres, MySQL and SQL Server?

No — this varies more than most people expect. Postgres accepts || for string concatenation alongside CONCAT(); SQL Server uses LEN() instead of LENGTH(); date arithmetic syntax (DATEADD vs DATE_ADD vs interval math) differs across all three. Always confirm the exact function name for your specific engine rather than assuming this cheat sheet's names are universal.

What does HAVING do that WHERE can't?

HAVING filters on the result of an aggregate function (like COUNT(*) or SUM(total)) after GROUP BY has run. WHERE runs before GROUP BY, so at that point no aggregates exist yet to filter on — that's the entire reason HAVING exists as a separate clause.

What happens if I run UPDATE or DELETE without a WHERE clause?

It applies to every row in the table — there's no implicit safety limit. Double-checking the WHERE clause before executing an UPDATE or DELETE, especially against a production database, is worth the extra few seconds every time.

Last updated