SQL Quick Reference

Essential SQL queries, JOINs, aggregation, subqueries, and data modification commands.

SELECT Basics

Select all columns from a table SELECT * FROM users;
Select specific columns SELECT name, email FROM users;
Filter rows with a condition SELECT * FROM users WHERE age > 25;
Multiple conditions SELECT * FROM users WHERE age > 25 AND active = true;
Pattern matching SELECT * FROM users WHERE name LIKE 'J%';
Check for NULL values SELECT * FROM users WHERE email IS NOT NULL;
Match against a list SELECT * FROM users WHERE role IN ('admin', 'editor');
Range filter SELECT * FROM users WHERE age BETWEEN 18 AND 65;
Remove duplicate rows SELECT DISTINCT city FROM users;
Sort results ascending SELECT * FROM users ORDER BY name ASC;
Sort results descending SELECT * FROM users ORDER BY created_at DESC;
Limit number of results SELECT * FROM users LIMIT 10;
Pagination with offset SELECT * FROM users LIMIT 10 OFFSET 20;
Column alias SELECT name AS full_name FROM users;

JOINs

Returns rows with matching values in both tables SELECT * FROM orders INNER JOIN users ON orders.user_id = users.id;
Returns all rows from left table + matched rows from right SELECT * FROM users LEFT JOIN orders ON users.id = orders.user_id;
Returns all rows from right table + matched rows from left SELECT * FROM orders RIGHT JOIN users ON orders.user_id = users.id;
Returns all rows when there is a match in either table SELECT * FROM users FULL OUTER JOIN orders ON users.id = orders.user_id;
Returns the Cartesian product of both tables SELECT * FROM sizes CROSS JOIN colors;
Join a table with itself SELECT e.name, m.name AS manager FROM employees e LEFT JOIN employees m ON e.manager_id = m.id;

Aggregation

Count the number of rows SELECT COUNT(*) FROM users;
Count non-NULL values SELECT COUNT(email) FROM users;
Sum of a column SELECT SUM(amount) FROM orders;
Average of a column SELECT AVG(price) FROM products;
Minimum value SELECT MIN(price) FROM products;
Maximum value SELECT MAX(price) FROM products;
Group results by a column SELECT city, COUNT(*) FROM users GROUP BY city;
Filter grouped results SELECT city, COUNT(*) AS cnt FROM users GROUP BY city HAVING cnt > 10;
Aggregate with multiple groups SELECT country, city, COUNT(*) FROM users GROUP BY country, city;

Subqueries & CTEs

Subquery in WHERE clause SELECT * FROM users WHERE id IN (SELECT user_id FROM orders);
Subquery as derived table SELECT avg_total FROM ( SELECT AVG(total) AS avg_total FROM orders ) AS sub;
Check if subquery returns rows SELECT * FROM users u WHERE EXISTS ( SELECT 1 FROM orders o WHERE o.user_id = u.id );
Common Table Expression (CTE) WITH active_users AS ( SELECT * FROM users WHERE active = true ) SELECT * FROM active_users;
Multiple CTEs WITH cte1 AS (SELECT ...), cte2 AS (SELECT ...) SELECT * FROM cte1 JOIN cte2 ...;
Recursive CTE WITH RECURSIVE tree AS ( SELECT id, name, parent_id, 0 AS depth FROM categories WHERE parent_id IS NULL UNION ALL SELECT c.id, c.name, c.parent_id, t.depth + 1 FROM categories c JOIN tree t ON c.parent_id = t.id ) SELECT * FROM tree;

Data Modification

Insert a single row INSERT INTO users (name, email) VALUES ('Alice', '[email protected]');
Insert multiple rows INSERT INTO users (name, email) VALUES ('Alice', '[email protected]'), ('Bob', '[email protected]');
Insert from a select INSERT INTO archive SELECT * FROM orders WHERE created_at < '2024-01-01';
Update rows UPDATE users SET name = 'Bob' WHERE id = 1;
Update with join (PostgreSQL) UPDATE orders SET status = 'shipped' FROM users WHERE orders.user_id = users.id AND users.premium = true;
Delete rows DELETE FROM users WHERE active = false;
Upsert (PostgreSQL) INSERT INTO users (email, name) VALUES ('[email protected]', 'Alice') ON CONFLICT (email) DO UPDATE SET name = EXCLUDED.name;
Upsert (MySQL) INSERT INTO users (email, name) VALUES ('[email protected]', 'Alice') ON DUPLICATE KEY UPDATE name = VALUES(name);
Truncate a table (fast delete all) TRUNCATE TABLE logs;

Constraints & Indexes

Primary key CREATE TABLE users ( id SERIAL PRIMARY KEY, name VARCHAR(100) );
Foreign key CREATE TABLE orders ( id SERIAL PRIMARY KEY, user_id INT REFERENCES users(id) );
Unique constraint ALTER TABLE users ADD CONSTRAINT uq_email UNIQUE (email);
NOT NULL constraint ALTER TABLE users ALTER COLUMN name SET NOT NULL;
Check constraint ALTER TABLE users ADD CONSTRAINT chk_age CHECK (age >= 0);
Create an index CREATE INDEX idx_users_email ON users (email);
Create a unique index CREATE UNIQUE INDEX idx_users_email ON users (email);
Composite index CREATE INDEX idx_name_city ON users (last_name, city);
Drop an index DROP INDEX idx_users_email;