Skip to content

SQL Cheat Sheet — Complete Reference (60+ queries, 2026)

Last verified May 2026 — runs in your browser
SQL Cheatsheet
SELECT * FROM users

Select all columns from table

Select
SELECT name, email FROM users

Select specific columns

Select
SELECT DISTINCT status FROM orders

Select unique values only

Select
SELECT * FROM users WHERE age > 18

Filter rows with WHERE

Select
SELECT * FROM users WHERE name LIKE '%john%'

Pattern matching with LIKE

Select
SELECT * FROM users WHERE age BETWEEN 18 AND 30

Range filter with BETWEEN

Select
SELECT * FROM users WHERE status IN ('active', 'pending')

Filter by set of values

Select
SELECT * FROM users WHERE email IS NOT NULL

Filter null/not null values

Select
SELECT * FROM users ORDER BY name ASC

Sort results ascending

Select
SELECT * FROM users ORDER BY created_at DESC LIMIT 10

Get top N rows

Select
SELECT * FROM users LIMIT 10 OFFSET 20

Pagination with offset

Select
SELECT name AS full_name FROM users

Column alias

Select
INSERT INTO users (name, email) VALUES ('John', 'john@mail.com')

Insert a row

Modify
INSERT INTO users (name, email) VALUES ('A', 'a@m.com'), ('B', 'b@m.com')

Insert multiple rows

Modify
UPDATE users SET name = 'Jane' WHERE id = 1

Update rows matching condition

Modify
DELETE FROM users WHERE id = 1

Delete rows matching condition

Modify
TRUNCATE TABLE users

Delete all rows (fast, no rollback)

Modify
INSERT INTO target SELECT * FROM source WHERE condition

Insert from another query

Modify
INSERT INTO users (name, email) VALUES ('John', 'j@m.com') ON CONFLICT (email) DO UPDATE SET name = EXCLUDED.name

Upsert (insert or update)

Modify
SELECT * FROM users INNER JOIN orders ON users.id = orders.user_id

Inner join (matching rows only)

Joins
SELECT * FROM users LEFT JOIN orders ON users.id = orders.user_id

Left join (all from left table)

Joins
SELECT * FROM users RIGHT JOIN orders ON users.id = orders.user_id

Right join (all from right table)

Joins
SELECT * FROM users FULL OUTER JOIN orders ON users.id = orders.user_id

Full outer join (all from both)

Joins
SELECT * FROM users CROSS JOIN products

Cross join (cartesian product)

Joins
SELECT a.name, b.name FROM employees a JOIN employees b ON a.manager_id = b.id

Self join

Joins
SELECT COUNT(*) FROM users

Count all rows

Aggregate
SELECT COUNT(DISTINCT status) FROM orders

Count distinct values

Aggregate
SELECT SUM(amount) FROM orders

Sum of column values

Aggregate
SELECT AVG(age) FROM users

Average of column values

Aggregate
SELECT MIN(price), MAX(price) FROM products

Min and max values

Aggregate
SELECT status, COUNT(*) FROM orders GROUP BY status

Group and count

Aggregate
SELECT status, COUNT(*) FROM orders GROUP BY status HAVING COUNT(*) > 5

Filter groups with HAVING

Aggregate
SELECT department, STRING_AGG(name, ', ') AS members FROM employees GROUP BY department

Concatenate grouped values

Aggregate
SELECT * FROM users WHERE id IN ( SELECT user_id FROM orders )

Subquery with IN

Subqueries
SELECT * FROM users WHERE EXISTS ( SELECT 1 FROM orders WHERE orders.user_id = users.id )

Subquery with EXISTS

Subqueries
SELECT *, ( SELECT COUNT(*) FROM orders WHERE orders.user_id = users.id ) AS order_count FROM users

Correlated subquery in SELECT

Subqueries
WITH active_users AS ( SELECT * FROM users WHERE status = 'active' ) SELECT * FROM active_users

Common Table Expression (CTE)

Subqueries
SELECT * FROM ( SELECT *, ROW_NUMBER() OVER (ORDER BY score DESC) AS rank FROM students ) ranked WHERE rank <= 10

Subquery with window function

Subqueries
CREATE TABLE users ( id SERIAL PRIMARY KEY, name VARCHAR(100) NOT NULL, email VARCHAR(255) UNIQUE, created_at TIMESTAMP DEFAULT NOW() )

Create table with constraints

DDL
ALTER TABLE users ADD COLUMN age INT

Add column to table

DDL
ALTER TABLE users DROP COLUMN age

Remove column from table

DDL
ALTER TABLE users ALTER COLUMN name SET NOT NULL

Modify column constraint

DDL
DROP TABLE IF EXISTS users

Drop table if it exists

DDL
ALTER TABLE users RENAME COLUMN name TO full_name

Rename column

DDL
ALTER TABLE orders ADD FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE

Add foreign key constraint

DDL
COALESCE(val1, val2, 'default')

Return first non-null value

Functions
CASE WHEN age < 18 THEN 'minor' WHEN age < 65 THEN 'adult' ELSE 'senior' END

Conditional expression

Functions
CAST(price AS INTEGER)

Type casting

Functions
CONCAT(first_name, ' ', last_name)

Concatenate strings

Functions
UPPER(name) / LOWER(name)

Convert case

Functions
LENGTH(name) / TRIM(name)

String length / trim whitespace

Functions
NOW() / CURRENT_DATE / CURRENT_TIMESTAMP

Current date/time

Functions
EXTRACT(YEAR FROM created_at)

Extract part from date

Functions
DATE_TRUNC('month', created_at)

Truncate date to precision

Functions
CREATE INDEX idx_users_email ON users(email)

Create index on column

Indexes
CREATE UNIQUE INDEX idx_users_email ON users(email)

Create unique index

Indexes
CREATE INDEX idx_name_email ON users(name, email)

Composite index (multi-column)

Indexes
DROP INDEX idx_users_email

Remove an index

Indexes
EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'x'

Analyze query execution plan

Indexes
Showing 59 of 59 queries

SQL Cheat Sheet — SELECT, JOIN, GROUP BY & Window Functions Reference

SQL was standardized in 1986 and the core dialect — SELECT, JOIN, GROUP BY, INSERT, UPDATE, DELETE — has barely shifted in forty years; CTEs and window functions sit on top of the same shape. The cheatsheet below covers 60+ queries across selects, modifications, joins, aggregates, subqueries, DDL, functions, and indexes. Most trouble in real queries doesn't come from forgetting syntax. It comes from quirks that look ordinary but bite. `NULL` is not equal to anything — including itself — so `WHERE column = NULL` returns no rows and the correct form is `IS NULL`. A `LEFT JOIN` followed by a `WHERE` filtering on the right table silently turns into an `INNER JOIN`, because any row with `NULL` on the right fails the filter. `COUNT(*)` and `COUNT(column)` return different numbers on identical-looking queries. The snippets below are the ones an author reaches for when debugging exactly that — the join that preserves the left side, the `HAVING` that filters groups not rows, the CTE that flattens a nested subquery — without rereading the SQL reference from line one each time.

Common pitfalls in SQL

A few patterns earn their place on the first screen of any SQL file. `WHERE` filters rows before grouping; `HAVING` filters groups after aggregation — putting `COUNT(*) > 5` in `WHERE` raises an error. Joining tables changes row counts: a one-to-many join multiplies, and a `SUM` over the joined result can double-count if the same parent row matches several children. Indexes pay off on columns that appear in `WHERE`, `JOIN ON`, or `ORDER BY` when selectivity is high enough to offset the write cost on every insert; `EXPLAIN ANALYZE` is the way to confirm an index is actually being used. `LIKE 'pattern%'` can use a btree index when the wildcard is at the end, but `LIKE '%pattern'` cannot, so leading wildcards force a full table scan. Transactions and isolation levels matter: the default `READ COMMITTED` lets two reads inside the same transaction see different values, fine for most reports but wrong for balance checks. The cheatsheet groups all of this into Select, Modify, Joins, Aggregate, Subqueries, DDL, Functions, and Indexes so the right section is one click away.

  • 60+ practical SQL queries
  • 8 categories from SELECT to indexes
  • Covers JOINs, CTEs, and window functions
  • DDL statements for table management
  • One-click copy to clipboard
  • PostgreSQL-compatible syntax

Free. No signup. Your inputs stay in your browser. Ads via Google AdSense (consent required).