All cheat sheets

SQL

SQL query reference: SELECT, JOINs, aggregation, subqueries, CTEs, window functions, data modification, and schema commands with practical examples.

Cheat Sheet

SQL (Structured Query Language) is the standard language for managing and querying relational databases. While each database has its own dialect (PostgreSQL, MySQL, SQLite, SQL Server…), the core syntax shown here works across all major engines.

Note: Dialects differ. Auto-increment (SERIAL vs AUTO_INCREMENT), date functions, and string concatenation (|| vs +) vary between engines. Examples use the most portable form.

Query Basics

ClauseExampleWhat it does
SELECTSELECT name, email FROM usersRetrieve specific columns from a table.
WHEREWHERE age >= 18 AND status = 'active'Filter rows based on conditions. Supports AND / OR / NOT, comparisons, IN, BETWEEN, LIKE.
ORDER BYORDER BY created_at DESC, name ASCSort results. ASC (default) or DESC. Multiple columns = multi-level sort.
LIMITLIMIT 10 OFFSET 20Limit the number of rows returned. OFFSET skips rows (for pagination).
DISTINCTSELECT DISTINCT category FROM productsReturn only unique rows. Duplicate values are collapsed to one.
AS (alias)SELECT COUNT(*) AS total FROM ordersRename a column or table for the query output (alias).

JOINs

SELECT * FROM a INNER JOIN b ON a.id = b.a_id

INNER JOIN

Returns rows where the condition matches in BOTH tables. Most common join.

SELECT * FROM a LEFT JOIN b ON a.id = b.a_id

LEFT JOIN

Returns ALL rows from the left table, plus matched rows from the right. Missing matches = NULL.

SELECT * FROM a RIGHT JOIN b ON a.id = b.a_id

RIGHT JOIN

Returns ALL rows from the right table, plus matched rows from the left.

SELECT * FROM a FULL JOIN b ON a.id = b.a_id

FULL OUTER JOIN

Returns all rows from both tables. NULL where no match exists.

SELECT * FROM a CROSS JOIN b

CROSS JOIN

Cartesian product: every row of A × every row of B. Use with caution.

SELECT e.name, m.name FROM emp e JOIN emp m ON e.mgr_id = m.id

SELF JOIN

A table joined with itself. Useful for hierarchies (e.g., employees + managers).

Aggregation & Grouping

FunctionExampleWhat it does
COUNTCOUNT(*) / COUNT(DISTINCT col)Counts rows or non-null values. COUNT(*) includes NULLs; COUNT(col) excludes them.
SUMSUM(amount)Sum of numeric values in a column.
AVGAVG(price)Average (mean) of numeric values.
MIN / MAXMIN(price), MAX(price)Smallest and largest value in a column. Works with text and dates too.
GROUP BYGROUP BY categoryGroups rows by column value. Must be used with aggregate functions. Every non-aggregated column in SELECT must be in GROUP BY.
HAVINGHAVING COUNT(*) > 5Filters groups AFTER aggregation (WHERE filters rows BEFORE). Required for conditions on aggregate results.

Common Functions & Expressions

ExpressionExampleWhat it does
CASECASE WHEN status = 'active' THEN 'on' ELSE 'off' ENDInline conditional. Evaluates WHENs in order and returns the first true branch. The simple form (CASE col WHEN value) works for equality checks.
COALESCECOALESCE(email, phone, 'none')Returns the first non-NULL argument. The standard way to supply fallback values for missing fields in reports.
NULLIFtotal / NULLIF(items, 0)Returns NULL when both arguments are equal. The clean way to avoid divide-by-zero: the division yields NULL instead of erroring.
IS NULLWHERE deleted_at IS NULLNULL comparisons require IS NULL / IS NOT NULL. Using = NULL evaluates to unknown and matches nothing.
CASTCAST(total AS DECIMAL(10,2))Explicit type conversion. PostgreSQL also supports the shorthand :: (e.g., total::numeric).
String fnsUPPER(name), LOWER(name), CONCAT(a, b), LENGTH(str)Case conversion, concatenation, and length. || is the concat operator in PostgreSQL/SQLite; SQL Server uses +. LENGTH is LEN() there.
Date fnsCURRENT_DATE, NOW(), DATE_TRUNC('month', created_at)Current date/time and date arithmetic. DATE_TRUNC is PostgreSQL; MySQL uses YEAR()/MONTH()/DATE_FORMAT().

Subqueries & CTEs

1

Scalar Subquery (single value)

SELECT name, (SELECT MAX(price) FROM products) AS max_price
FROM users;

Returns a single value used in an expression. Must return exactly one row and one column.

2

Row Subquery (IN / EXISTS)

SELECT * FROM orders
WHERE customer_id IN (
  SELECT id FROM customers
  WHERE status = 'vip'
);

Use IN for list-of-values results. EXISTS is more efficient for large datasets: it returns true/false per outer row.

3

CTE (WITH clause)

WITH sales_cte AS (
  SELECT region, SUM(amount) AS total
  FROM orders
  GROUP BY region
)
SELECT * FROM sales_cte
WHERE total > 10000;

A named temporary result set. Makes complex queries readable. Can reference itself recursively (e.g., for trees).

4

Recursive CTE (tree hierarchy)

WITH RECURSIVE org AS (
  SELECT id, name, manager_id, 1 AS level
  FROM employees WHERE manager_id IS NULL
  UNION ALL
  SELECT e.id, e.name, e.manager_id, org.level + 1
  FROM employees e
  JOIN org ON e.manager_id = org.id
)
SELECT * FROM org;

Walks a tree structure level by level. Anchor = root(s), recursive step = children. UNION ALL stops when no new rows found.

Window Functions

FunctionExampleWhat it does
ROW_NUMBER()ROW_NUMBER() OVER (ORDER BY score DESC)Assigns a unique sequential integer to each row within the partition, starting at 1.
RANK()RANK() OVER (ORDER BY score DESC)Like ROW_NUMBER but ties share same rank. The next rank skips values (1, 1, 3).
DENSE_RANK()DENSE_RANK() OVER (ORDER BY score DESC)Like RANK but without gaps. Ties share same rank, next is the following integer (1, 1, 2).
LAG()LAG(amount, 1) OVER (ORDER BY date)Access the value from the previous row within the partition. Great for day-over-day comparisons.
LEAD()LEAD(amount, 1) OVER (ORDER BY date)Access the value from the next row within the partition.
FIRST_VALUE()FIRST_VALUE(amount) OVER (ORDER BY date)Returns the first value in the ordered window frame.
NTILE(n)NTILE(4) OVER (ORDER BY score DESC)Divides rows into n buckets (roughly equal size). Useful for quartiles/percentiles.

Data Modification

CommandExampleWhat it does
INSERTINSERT INTO users (name, email) VALUES ('Alice', 'a@b.com')Adds a new row. Can insert multiple rows in one statement with comma-separated VALUES.
UPDATEUPDATE users SET email = 'new@b.com' WHERE id = 1Modifies existing rows. Always add a WHERE clause: UPDATE without WHERE updates ALL rows.
DELETEDELETE FROM users WHERE last_login IS NULLRemoves rows matching the condition. DELETE without WHERE empties the table.
UPSERTINSERT INTO users (id, name) VALUES (1, 'Bob') ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.namePostgreSQL-style insert-or-update. MySQL uses INSERT … ON DUPLICATE KEY UPDATE. SQLite uses INSERT OR REPLACE.
TRUNCATETRUNCATE TABLE logsDeletes ALL rows quickly (cannot be filtered). Resets storage and is faster than DELETE for full table clears.

Schema & DDL

CommandExampleWhat it does
CREATE TABLECREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT NOT NULL, email TEXT UNIQUE)Creates a new table with columns, types, and constraints.
ALTER TABLEALTER TABLE users ADD COLUMN age INT DEFAULT 0Modifies an existing table: add/drop columns, change types, rename, add constraints.
DROP TABLEDROP TABLE IF EXISTS temp_dataRemoves a table and all its data permanently.
CREATE INDEXCREATE INDEX idx_email ON users (email)Speeds up queries on the indexed column(s). Composite indexes work on multi-column queries.
CREATE VIEWCREATE VIEW active_users AS SELECT * FROM users WHERE status = 'active'A saved query that behaves like a virtual table. Great for encapsulating complex logic.
ConstraintsNOT NULL, UNIQUE, PRIMARY KEY, FOREIGN KEY, CHECK, DEFAULTEnforce data integrity at the schema level. CHECK validates a boolean expression. DEFAULT sets a fallback value.

Try our SQL Formatter →

Format, beautify, and lint your SQL queries instantly.

OCMA Tools

Free developer tools. Most features run client-side, your data stays in your browser. Optional accounts unlock extra features.

Most tools run client-side

© 2026 OCMA Tools — Free developer tools

built for developers, by developers