SQL Reference

SQL Cheat Sheet: Every Command You Need in One Page (2026)

A complete SQL reference covering every command from basic CRUD operations to window functions, CTEs, and query optimization. Bookmark this page and stop Googling SQL syntax.

Mar 10, 2026 15 min read

Basic SQL Commands

These four commands form the foundation of SQL. Every query you write uses at least one of them.

SELECT - Read data

-- Select specific columns
SELECT first_name, last_name, email
FROM users;

-- Select all columns
SELECT * FROM products;

-- Select with alias
SELECT first_name AS name, email AS contact
FROM users;

INSERT - Add new rows

-- Insert a single row
INSERT INTO users (first_name, last_name, email)
VALUES ('Jane', 'Smith', 'jane@example.com');

-- Insert multiple rows
INSERT INTO users (first_name, last_name, email)
VALUES
    ('Alice', 'Johnson', 'alice@example.com'),
    ('Bob', 'Williams', 'bob@example.com');

UPDATE - Modify existing rows

-- Update specific rows
UPDATE users
SET email = 'newemail@example.com'
WHERE id = 42;

-- Update multiple columns
UPDATE products
SET price = price * 1.10, updated_at = NOW()
WHERE category = 'electronics';

DELETE - Remove rows

-- Delete specific rows
DELETE FROM orders
WHERE status = 'cancelled' AND created_at < '2025-01-01';

-- Delete all rows (use with caution)
DELETE FROM temp_logs;

Filtering and Sorting

Control which rows are returned and in what order.

WHERE, AND, OR

SELECT * FROM orders
WHERE status = 'shipped'
  AND total_amount > 100
  AND (region = 'US' OR region = 'EU');

IN and BETWEEN

-- IN: match any value in a list
SELECT * FROM products
WHERE category IN ('electronics', 'books', 'clothing');

-- BETWEEN: inclusive range
SELECT * FROM orders
WHERE order_date BETWEEN '2026-01-01' AND '2026-03-31';

LIKE - Pattern matching

-- % matches any sequence of characters
SELECT * FROM users WHERE email LIKE '%@gmail.com';

-- _ matches exactly one character
SELECT * FROM products WHERE sku LIKE 'SKU-____';

ORDER BY and LIMIT

-- Sort ascending (default) and descending
SELECT product_name, price
FROM products
ORDER BY price DESC;

-- Limit results (pagination)
SELECT * FROM users
ORDER BY created_at DESC
LIMIT 20 OFFSET 40;  -- Page 3, 20 per page

Aggregation Functions

Summarize data across multiple rows into a single result.

COUNT, SUM, AVG, MIN, MAX

SELECT
    COUNT(*) AS total_orders,
    SUM(total_amount) AS revenue,
    AVG(total_amount) AS avg_order_value,
    MIN(total_amount) AS smallest_order,
    MAX(total_amount) AS largest_order
FROM orders
WHERE order_date >= '2026-01-01';

GROUP BY

-- Revenue by category
SELECT
    category,
    COUNT(*) AS num_products,
    SUM(price) AS total_value
FROM products
GROUP BY category
ORDER BY total_value DESC;

HAVING - Filter groups

-- Only show categories with more than 10 products
SELECT category, COUNT(*) AS num_products
FROM products
GROUP BY category
HAVING COUNT(*) > 10
ORDER BY num_products DESC;

Remember: WHERE filters rows before grouping. HAVING filters groups after aggregation.

JOINs

Combine rows from two or more tables based on a related column.

INNER JOIN - Only matching rows from both tables

SELECT o.id, o.order_date, c.name, c.email
FROM orders o
INNER JOIN customers c ON o.customer_id = c.id;

LEFT JOIN - All rows from left table, matching from right

-- All customers, even those with no orders
SELECT c.name, COUNT(o.id) AS order_count
FROM customers c
LEFT JOIN orders o ON c.id = o.customer_id
GROUP BY c.name;

RIGHT JOIN - All rows from right table, matching from left

-- All products, even those never ordered
SELECT p.product_name, SUM(oi.quantity) AS total_sold
FROM order_items oi
RIGHT JOIN products p ON oi.product_id = p.id
GROUP BY p.product_name;

FULL OUTER JOIN - All rows from both tables

-- Show all customers and all orders, matched where possible
SELECT c.name, o.id AS order_id
FROM customers c
FULL OUTER JOIN orders o ON c.id = o.customer_id;

CROSS JOIN - Every combination of rows

-- Generate all size/color combinations
SELECT s.size_name, c.color_name
FROM sizes s
CROSS JOIN colors c;

Quick reference: INNER = intersection, LEFT = all left + matching right (NULLs for no match), RIGHT = mirror of LEFT, FULL = union of both sides, CROSS = cartesian product.

Subqueries and CTEs

Break complex queries into manageable parts.

Subquery in WHERE

-- Customers who placed orders over $500
SELECT name, email
FROM customers
WHERE id IN (
    SELECT customer_id
    FROM orders
    WHERE total_amount > 500
);

EXISTS

-- Products that have been ordered at least once
SELECT p.product_name
FROM products p
WHERE EXISTS (
    SELECT 1
    FROM order_items oi
    WHERE oi.product_id = p.id
);

CTE (Common Table Expression) with WITH

-- Monthly revenue with running total
WITH monthly_revenue AS (
    SELECT
        DATE_TRUNC('month', order_date) AS month,
        SUM(total_amount) AS revenue
    FROM orders
    GROUP BY DATE_TRUNC('month', order_date)
)
SELECT
    month,
    revenue,
    SUM(revenue) OVER (ORDER BY month) AS running_total
FROM monthly_revenue
ORDER BY month;

Multiple CTEs

WITH active_users AS (
    SELECT user_id, COUNT(*) AS logins
    FROM login_events
    WHERE event_date >= CURRENT_DATE - INTERVAL '30 days'
    GROUP BY user_id
),
user_orders AS (
    SELECT user_id, SUM(total_amount) AS total_spent
    FROM orders
    WHERE order_date >= CURRENT_DATE - INTERVAL '30 days'
    GROUP BY user_id
)
SELECT
    u.name,
    a.logins,
    COALESCE(uo.total_spent, 0) AS total_spent
FROM users u
JOIN active_users a ON u.id = a.user_id
LEFT JOIN user_orders uo ON u.id = uo.user_id
ORDER BY a.logins DESC;

Window Functions

Perform calculations across a set of rows related to the current row, without collapsing them into a single output row.

ROW_NUMBER, RANK, DENSE_RANK

SELECT
    name,
    department,
    salary,
    ROW_NUMBER() OVER (ORDER BY salary DESC) AS row_num,
    RANK() OVER (ORDER BY salary DESC) AS rank,
    DENSE_RANK() OVER (ORDER BY salary DESC) AS dense_rank
FROM employees;

ROW_NUMBER gives unique sequential numbers. RANK leaves gaps after ties (1,2,2,4). DENSE_RANK has no gaps (1,2,2,3).

PARTITION BY

-- Rank employees within each department
SELECT
    name,
    department,
    salary,
    RANK() OVER (
        PARTITION BY department
        ORDER BY salary DESC
    ) AS dept_rank
FROM employees;

LAG and LEAD

-- Compare each month's revenue to the previous month
SELECT
    month,
    revenue,
    LAG(revenue, 1) OVER (ORDER BY month) AS prev_month,
    revenue - LAG(revenue, 1) OVER (ORDER BY month) AS month_over_month
FROM monthly_revenue;

String Functions

Manipulate and transform text data.

-- CONCAT: combine strings
SELECT CONCAT(first_name, ' ', last_name) AS full_name
FROM users;

-- UPPER / LOWER: change case
SELECT UPPER(email) FROM users;
SELECT LOWER(city) FROM addresses;

-- SUBSTRING: extract part of a string
SELECT SUBSTRING(phone FROM 1 FOR 3) AS area_code
FROM contacts;

-- TRIM: remove whitespace
SELECT TRIM(name) FROM products;

-- REPLACE: substitute text
SELECT REPLACE(url, 'http://', 'https://') FROM links;

-- LENGTH: count characters
SELECT name, LENGTH(name) AS name_length
FROM products
WHERE LENGTH(name) > 50;

Date Functions

Work with dates and timestamps. Syntax varies by database; these examples use PostgreSQL-style syntax.

-- NOW: current timestamp
SELECT NOW();

-- DATE_TRUNC: round down to a unit
SELECT DATE_TRUNC('month', order_date) AS order_month
FROM orders;

-- EXTRACT: pull out a date part
SELECT EXTRACT(YEAR FROM order_date) AS order_year,
       EXTRACT(MONTH FROM order_date) AS order_month
FROM orders;

-- Date arithmetic
SELECT order_date,
       order_date + INTERVAL '7 days' AS one_week_later
FROM orders;

-- DATEDIFF (SQL Server / MySQL style)
SELECT DATEDIFF(day, ship_date, delivery_date) AS transit_days
FROM shipments;

-- AGE (PostgreSQL): difference between dates
SELECT AGE(NOW(), created_at) AS account_age
FROM users;

-- Filter by relative dates
SELECT * FROM orders
WHERE order_date >= CURRENT_DATE - INTERVAL '30 days';

Table Operations

Define and modify your database structure.

CREATE TABLE

CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    first_name VARCHAR(100) NOT NULL,
    last_name VARCHAR(100) NOT NULL,
    email VARCHAR(255) UNIQUE NOT NULL,
    created_at TIMESTAMP DEFAULT NOW(),
    is_active BOOLEAN DEFAULT true
);

ALTER TABLE

-- Add a column
ALTER TABLE users ADD COLUMN phone VARCHAR(20);

-- Change a column type
ALTER TABLE products ALTER COLUMN price TYPE NUMERIC(10,2);

-- Add a constraint
ALTER TABLE orders ADD CONSTRAINT fk_customer
    FOREIGN KEY (customer_id) REFERENCES customers(id);

-- Drop a column
ALTER TABLE users DROP COLUMN phone;

DROP TABLE

-- Drop if exists (safe)
DROP TABLE IF EXISTS temp_imports;

-- Drop with cascade (removes dependent objects)
DROP TABLE IF EXISTS old_orders CASCADE;

Indexes

-- Create an index for faster lookups
CREATE INDEX idx_users_email ON users(email);

-- Composite index
CREATE INDEX idx_orders_customer_date
ON orders(customer_id, order_date);

-- Unique index
CREATE UNIQUE INDEX idx_users_email_unique ON users(email);

-- Drop an index
DROP INDEX IF EXISTS idx_users_email;

Pro Tips

Write faster, more efficient queries.

EXPLAIN - Understand query performance

-- See the query execution plan
EXPLAIN ANALYZE
SELECT c.name, COUNT(o.id)
FROM customers c
JOIN orders o ON c.id = o.customer_id
GROUP BY c.name;

Look for sequential scans on large tables. If you see one, an index on the JOIN or WHERE column usually fixes it.

Query optimization basics

  • Select only the columns you need. Avoid SELECT * in production queries. It reads unnecessary data and breaks when schema changes.
  • Filter early. Put WHERE conditions that eliminate the most rows first. The database optimizer handles this in most cases, but explicit filtering in subqueries and CTEs helps with complex queries.
  • Use EXISTS instead of IN for large subqueries. EXISTS stops at the first match, while IN may evaluate the entire subquery.
  • Index your JOIN and WHERE columns. If you frequently filter by status or join on customer_id, those columns should have indexes.
  • Avoid functions on indexed columns in WHERE. WHERE YEAR(created_at) = 2026 cannot use an index on created_at. Use WHERE created_at >= '2026-01-01' AND created_at < '2027-01-01' instead.
  • Use LIMIT during development. Add LIMIT 100 while building queries to avoid accidentally scanning millions of rows.

Try these queries instantly - AI2SQL generates SQL from plain English so you can skip the syntax and focus on the data you need.

Frequently Asked Questions

What should a SQL cheat sheet include?

A comprehensive SQL cheat sheet should cover SELECT, INSERT, UPDATE, DELETE, JOINs (INNER, LEFT, RIGHT, FULL), aggregation functions (COUNT, SUM, AVG), filtering (WHERE, HAVING), subqueries, CTEs, window functions, string functions, date functions, and table DDL operations. It should also include syntax examples for each command.

Is SQL syntax the same across all databases?

Core SQL syntax (SELECT, INSERT, UPDATE, DELETE, JOINs) is largely the same across databases. However, date functions, string functions, window function syntax, and features like LIMIT vs TOP vary between PostgreSQL, MySQL, SQL Server, Oracle, and SQLite. Always check your specific database dialect for edge cases.

What are the most important SQL commands to memorize?

The essential SQL commands to know are: SELECT (reading data), WHERE (filtering), JOIN (combining tables), GROUP BY with aggregate functions (summarizing data), ORDER BY (sorting), INSERT/UPDATE/DELETE (modifying data), and CREATE TABLE (defining schema). These cover 90% of daily SQL work.

How do I practice SQL commands from a cheat sheet?

The best way to practice is with a real database. Use a tool like AI2SQL with its built-in demo database to run queries instantly. You can also set up a local SQLite or PostgreSQL database, load sample data, and work through each command on the cheat sheet one by one.

Can AI generate SQL commands for me instead of memorizing them?

Yes. Tools like AI2SQL let you describe what you need in plain English and generate the correct SQL automatically. This is especially useful for complex queries involving multiple JOINs, window functions, or nested subqueries. However, understanding the fundamentals from a cheat sheet helps you verify and refine AI-generated queries.

Generate SQL from Plain English

Stop memorizing syntax. Describe what you need and let AI2SQL generate accurate queries for your database.

Try AI2SQL Free

No credit card required