SQL Cheat Sheet

Complete SQL quick reference — SELECT anatomy, JOINs, aggregation, subqueries, window functions, DDL, and common functions.

SELECT JOINs Aggregate Window Functions DDL & DML Functions

SELECT Anatomy

SELECT   col1, col2, agg_fn(col3)  -- what
FROM     table                       -- source
JOIN     other ON table.id = other.fk
WHERE    condition                   -- filter rows before group
GROUP BY col1, col2                  -- aggregate
HAVING   agg_condition               -- filter after group
ORDER BY col1 DESC                   -- sort
LIMIT    10 OFFSET 20;               -- pagination
SELECT DISTINCT col Unique values only
WHERE col LIKE '%text%' Pattern matching (% = any chars, _ = one char)
WHERE col IN (1, 2, 3) Match any value in list
WHERE col BETWEEN 10 AND 20 Inclusive range filter
WHERE col IS NULL Test for NULL (never use = NULL)
ORDER BY col ASC NULLS LAST Put NULLs at end of sort

JOINs

INNER JOIN Only matching rows from both tables
LEFT JOIN All rows from left, matched from right (NULL if no match)
RIGHT JOIN All rows from right, matched from left
FULL OUTER JOIN All rows from both tables, NULL where no match
CROSS JOIN Cartesian product — every row × every row
SELF JOIN Join a table with itself using aliases
UNION / UNION ALL Combine result sets; ALL keeps duplicates

Aggregate Functions

COUNT(*) Count all rows including NULLs
COUNT(col) Count non-NULL values
COUNT(DISTINCT col) Count unique non-NULL values
SUM(col) Sum of values (ignores NULL)
AVG(col) Average (ignores NULL)
MIN(col) / MAX(col) Minimum / maximum value
GROUP_CONCAT(col, ',') Concatenate group values (MySQL/SQLite)
STRING_AGG(col, ',') Concatenate group values (PostgreSQL/SQL Server)

Window Functions

fn() OVER (
  PARTITION BY department
  ORDER BY salary DESC
  ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
)
ROW_NUMBER() Sequential row number within partition
RANK() Rank with gaps for ties (1,1,3)
DENSE_RANK() Rank without gaps (1,1,2)
NTILE(n) Divide rows into n buckets
LAG(col, n) Value from n rows before current row
LEAD(col, n) Value from n rows after current row
FIRST_VALUE(col) First value in window frame
SUM(col) OVER (...) Running total (cumulative sum)

DDL & DML

INSERT INTO t (cols) VALUES (...) Insert a row
INSERT INTO t SELECT ... FROM ... Insert from query result
UPDATE t SET col=val WHERE ... Update rows matching condition
DELETE FROM t WHERE ... Delete rows (always use WHERE!)
CREATE TABLE t (col type, ...) Create table with column definitions
ALTER TABLE t ADD COLUMN col type Add column to existing table
CREATE INDEX idx ON t (col) Create index for faster lookups
TRUNCATE TABLE t Delete all rows fast (no WHERE, no log)

Common Functions

COALESCE(a, b, c) First non-NULL value
NULLIF(a, b) NULL if a=b, else a (prevent div by zero)
CASE WHEN ... THEN ... END Conditional expression (if/else in SQL)
CAST(col AS type) Type conversion
UPPER(s) / LOWER(s) String case conversion
TRIM(s) / LTRIM / RTRIM Remove whitespace
NOW() / CURRENT_DATE Current timestamp / date
DATE_TRUNC('month', ts) Truncate timestamp to month (PostgreSQL)
WITH cte AS (SELECT ...) Common Table Expression (named subquery)

More Cheat Sheets