SQL cheatsheet

Comprehensive SQL command reference for querying, managing, and formatting database results

Querying Data

Select all columns from a table

SELECT * FROM table_name;

Select specific columns

SELECT column1, column2 FROM table_name;

Select with a condition

SELECT * FROM table_name WHERE column = 'value';

Select with multiple conditions (AND)

SELECT * FROM table_name WHERE column1 = 'value1' AND column2 = 'value2';

Select with multiple conditions (OR)

SELECT * FROM table_name WHERE column1 = 'value1' OR column2 = 'value2';

Select with LIKE pattern matching

SELECT * FROM table_name WHERE column LIKE '%pattern%';

Select with IN clause

SELECT * FROM table_name WHERE column IN ('value1', 'value2', 'value3');

Select with BETWEEN range

SELECT * FROM table_name WHERE column BETWEEN 10 AND 20;
Formatting Results for Sharing

Format record as key-value pairs (PostgreSQL)

Outputs a single text field with key-value pairs, one per line, perfect for copying and pasting into emails

SELECT 
  'name: ' || name || E'\n' ||
  'email: ' || email || E'\n' ||
  'city: ' || city || E'\n' ||
  'dateOfBirth: ' || dateOfBirth
  AS record_details
FROM users
WHERE name = 'Eric Byrd';

Format record as key-value pairs (MySQL)

MySQL version using CONCAT for combining fields with labels

SELECT 
  CONCAT(
    'name: ', name, '\n',
    'email: ', email, '\n',
    'city: ', city, '\n',
    'dateOfBirth: ', dateOfBirth
  ) AS record_details
FROM users
WHERE name = 'Eric Byrd';

Format all columns as key-value using JSON (PostgreSQL)

Automatically formats all columns as readable JSON with proper indentation

SELECT jsonb_pretty(to_jsonb(t)) AS formatted_record
FROM users t
WHERE name = 'Eric Byrd';

Format as vertical display (MySQL)

Use \G instead of ; to display results vertically in MySQL CLI

SELECT * FROM users WHERE name = 'Eric Byrd'\G
Sorting and Limiting

Order results ascending

SELECT * FROM table_name ORDER BY column ASC;

Order results descending

SELECT * FROM table_name ORDER BY column DESC;

Limit number of results

SELECT * FROM table_name LIMIT 10;

Limit with offset

SELECT * FROM table_name LIMIT 10 OFFSET 20;

Get top N results

SELECT * FROM table_name ORDER BY column DESC LIMIT 5;
Inserting Data

Insert a single row

INSERT INTO table_name (column1, column2) VALUES ('value1', 'value2');

Insert multiple rows

INSERT INTO table_name (column1, column2) VALUES 
  ('value1', 'value2'),
  ('value3', 'value4'),
  ('value5', 'value6');

Insert from another table

INSERT INTO table_name (column1, column2)
SELECT column1, column2 FROM other_table;
Updating Data

Update all rows

UPDATE table_name SET column = 'new_value';

Update with a condition

UPDATE table_name SET column = 'new_value' WHERE id = 1;

Update multiple columns

UPDATE table_name SET column1 = 'value1', column2 = 'value2' WHERE id = 1;

Increment a numeric value

UPDATE table_name SET count = count + 1 WHERE id = 1;
Deleting Data

Delete all rows (use with caution!)

DELETE FROM table_name;

Delete with a condition

DELETE FROM table_name WHERE id = 1;

Delete with multiple conditions

DELETE FROM table_name WHERE status = 'inactive' AND created_at < '2023-01-01';
Joins

Inner join

SELECT t1.*, t2.column
FROM table1 t1
INNER JOIN table2 t2 ON t1.id = t2.table1_id;

Left join

SELECT t1.*, t2.column
FROM table1 t1
LEFT JOIN table2 t2 ON t1.id = t2.table1_id;

Right join

SELECT t1.*, t2.column
FROM table1 t1
RIGHT JOIN table2 t2 ON t1.id = t2.table1_id;

Full outer join

SELECT t1.*, t2.column
FROM table1 t1
FULL OUTER JOIN table2 t2 ON t1.id = t2.table1_id;

Self join

SELECT e1.name AS employee, e2.name AS manager
FROM employees e1
LEFT JOIN employees e2 ON e1.manager_id = e2.id;
Aggregation

Count rows

SELECT COUNT(*) FROM table_name;

Count distinct values

SELECT COUNT(DISTINCT column) FROM table_name;

Sum values

SELECT SUM(column) FROM table_name;

Average value

SELECT AVG(column) FROM table_name;

Min and max values

SELECT MIN(column), MAX(column) FROM table_name;

Group by with count

SELECT column, COUNT(*) FROM table_name GROUP BY column;

Group by with having clause

SELECT column, COUNT(*) FROM table_name GROUP BY column HAVING COUNT(*) > 10;
Table Management

Create a table

CREATE TABLE table_name (
  id SERIAL PRIMARY KEY,
  name VARCHAR(100) NOT NULL,
  email VARCHAR(255) UNIQUE,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Drop a table

DROP TABLE table_name;

Drop table if exists

DROP TABLE IF EXISTS table_name;

Add a column

ALTER TABLE table_name ADD COLUMN new_column VARCHAR(50);

Drop a column

ALTER TABLE table_name DROP COLUMN column_name;

Rename a column

ALTER TABLE table_name RENAME COLUMN old_name TO new_name;

Modify column type

ALTER TABLE table_name ALTER COLUMN column_name TYPE VARCHAR(200);
Indexes

Create an index

CREATE INDEX idx_column ON table_name(column);

Create a unique index

CREATE UNIQUE INDEX idx_column ON table_name(column);

Create a composite index

CREATE INDEX idx_multiple ON table_name(column1, column2);

Drop an index

DROP INDEX idx_column;

List all indexes

SELECT * FROM pg_indexes WHERE tablename = 'table_name';
Transactions

Start a transaction

BEGIN;

Commit a transaction

COMMIT;

Rollback a transaction

ROLLBACK;

Transaction example

BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;
String Functions

Concatenate strings

SELECT CONCAT(first_name, ' ', last_name) FROM users;

Convert to uppercase

SELECT UPPER(column) FROM table_name;

Convert to lowercase

SELECT LOWER(column) FROM table_name;

Get string length

SELECT LENGTH(column) FROM table_name;

Trim whitespace

SELECT TRIM(column) FROM table_name;

Substring

SELECT SUBSTRING(column, 1, 10) FROM table_name;

Replace text

SELECT REPLACE(column, 'old', 'new') FROM table_name;
Date and Time

Get current date

SELECT CURRENT_DATE;

Get current timestamp

SELECT CURRENT_TIMESTAMP;

Extract year from date

SELECT EXTRACT(YEAR FROM date_column) FROM table_name;

Extract month from date

SELECT EXTRACT(MONTH FROM date_column) FROM table_name;

Date arithmetic (add days)

SELECT date_column + INTERVAL '7 days' FROM table_name;

Date difference

SELECT AGE(date_column1, date_column2) FROM table_name;

Format date

SELECT TO_CHAR(date_column, 'YYYY-MM-DD') FROM table_name;
Subqueries

Subquery in WHERE clause

SELECT * FROM table_name WHERE column > (SELECT AVG(column) FROM table_name);

Subquery with IN

SELECT * FROM table1 WHERE id IN (SELECT table1_id FROM table2 WHERE condition);

Subquery in SELECT

SELECT column, (SELECT COUNT(*) FROM table2 WHERE table2.id = table1.id) AS count FROM table1;

Correlated subquery

SELECT * FROM table1 t1 WHERE column > (SELECT AVG(column) FROM table1 t2 WHERE t2.category = t1.category);
Common Table Expressions (CTEs)

Basic CTE

WITH cte_name AS (
  SELECT column FROM table_name WHERE condition
)
SELECT * FROM cte_name;

Multiple CTEs

WITH cte1 AS (
  SELECT * FROM table1
),
cte2 AS (
  SELECT * FROM table2
)
SELECT * FROM cte1 JOIN cte2 ON cte1.id = cte2.id;

Recursive CTE

WITH RECURSIVE cte AS (
  SELECT id, parent_id, name, 1 AS level
  FROM categories WHERE parent_id IS NULL
  UNION ALL
  SELECT c.id, c.parent_id, c.name, cte.level + 1
  FROM categories c
  JOIN cte ON c.parent_id = cte.id
)
SELECT * FROM cte;
Window Functions

Row number

SELECT column, ROW_NUMBER() OVER (ORDER BY column) AS row_num FROM table_name;

Rank

SELECT column, RANK() OVER (ORDER BY column DESC) AS rank FROM table_name;

Partition by

SELECT column, COUNT(*) OVER (PARTITION BY category) AS category_count FROM table_name;

Running total

SELECT date, amount, SUM(amount) OVER (ORDER BY date) AS running_total FROM transactions;

Lead and lag

SELECT date, value, LAG(value) OVER (ORDER BY date) AS prev_value, LEAD(value) OVER (ORDER BY date) AS next_value FROM table_name;
Database Information

List all tables (PostgreSQL)

SELECT tablename FROM pg_tables WHERE schemaname = 'public';

List all tables (MySQL)

SHOW TABLES;

Describe table structure (PostgreSQL)

SELECT * FROM information_schema.columns WHERE table_name = 'table_name';

Describe table structure (MySQL)

DESCRIBE table_name;

Get database size (PostgreSQL)

SELECT pg_size_pretty(pg_database_size(current_database()));

Get table size (PostgreSQL)

SELECT pg_size_pretty(pg_total_relation_size('table_name'));
Enum Types

Drop all enum types (PostgreSQL)

Generates and executes DROP commands for every enum type in your PostgreSQL database. Run in TablePlus SQL query tab to remove all custom enum types.

DO $$
DECLARE
    r RECORD;
BEGIN
    FOR r IN (
        SELECT n.nspname AS schema_name, t.typname AS type_name
        FROM pg_type t
        JOIN pg_namespace n ON n.oid = t.typnamespace
        WHERE t.typtype = 'e'
          AND n.nspname NOT IN ('pg_catalog', 'information_schema')
    ) LOOP
        EXECUTE format('DROP TYPE IF EXISTS %I.%I CASCADE;', r.schema_name, r.type_name);
    END LOOP;
END $$;
Performance

Explain query plan

EXPLAIN SELECT * FROM table_name WHERE column = value;

Explain analyze (with execution)

EXPLAIN ANALYZE SELECT * FROM table_name WHERE column = value;

Vacuum table (PostgreSQL)

VACUUM table_name;

Analyze table statistics

ANALYZE table_name;
Note: SQL (Structured Query Language) is used to manage and query relational databases. This cheatsheet covers common SQL commands for PostgreSQL and MySQL. Commands may vary slightly between database systems. The Formatting Results for Sharing section shows how to format query results as key-value pairs, perfect for sharing database records with clients via email.
Webmaster Db