Limited Time Offer: 40% off

PostgreSQL

PostgreSQL Cheat Sheet

A complete reference of PostgreSQL syntax with 61 interactive examples. Copy code snippets or click “Try It” to run them directly in your browser.

Creating & Modifying Tables

CREATE TABLE

·

Create a new table with columns and constraints.

CREATE TABLE users (
  id SERIAL PRIMARY KEY,
  name TEXT NOT NULL,
  email TEXT UNIQUE,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Tip: Use SERIAL or BIGSERIAL for auto-incrementing IDs.

CREATE TABLE IF NOT EXISTS

·

Create a table only if it does not already exist.

CREATE TABLE IF NOT EXISTS logs (
  id SERIAL PRIMARY KEY,
  message TEXT,
  level TEXT DEFAULT 'info'
);

ALTER TABLE ADD

·

Add a new column to an existing table.

ALTER TABLE users ADD COLUMN phone TEXT;

ALTER TABLE ALTER COLUMN

·

Modify a column type or constraints.

ALTER TABLE users ALTER COLUMN name TYPE VARCHAR(100);

ALTER TABLE RENAME

·

Rename a table or column.

ALTER TABLE users RENAME COLUMN name TO full_name;

DROP TABLE

·

Delete a table and all its data.

DROP TABLE IF EXISTS temp_data CASCADE;

Tip: Use CASCADE to also drop dependent objects.

CREATE INDEX

·

Create an index to speed up queries.

CREATE INDEX idx_users_email ON users(email);

Tip: PostgreSQL supports B-tree, Hash, GIN, GiST, and BRIN indexes.

CREATE VIEW

·

Create a virtual table based on a SELECT query.

CREATE VIEW active_users AS
SELECT id, name, email FROM users
WHERE created_at > NOW() - INTERVAL '30 days';

CREATE SCHEMA

·

Create a namespace for database objects.

CREATE SCHEMA sales;
CREATE TABLE sales.orders (id SERIAL PRIMARY KEY);

Tip: Schemas help organize tables and control access.

Adding & Changing Data

INSERT

·

Add new rows to a table.

INSERT INTO users (name, email)
VALUES ('Dave Wilson', 'dave@example.com')
RETURNING *;

Tip: Use RETURNING to get the inserted row back.

INSERT Multiple Rows

·

Insert multiple rows in a single statement.

INSERT INTO products (name, category, price, stock) VALUES
  ('Headphones', 'Electronics', 149.99, 100),
  ('Webcam', 'Electronics', 89.99, 60)
RETURNING *;

UPDATE

·

Modify existing rows in a table.

UPDATE orders SET status = 'shipped'
WHERE id = 3
RETURNING *;

Tip: Always use WHERE to avoid updating all rows.

DELETE

·

Remove rows from a table.

DELETE FROM orders WHERE status = 'pending'
RETURNING *;

Tip: Use RETURNING to see what was deleted.

UPSERT (INSERT ON CONFLICT)

·

Insert a row or update it if a conflict occurs.

INSERT INTO users (id, name, email)
VALUES (1, 'Alice Updated', 'alice.new@example.com')
ON CONFLICT (id) DO UPDATE SET
  name = EXCLUDED.name,
  email = EXCLUDED.email
RETURNING *;

Tip: EXCLUDED refers to the row that would have been inserted.

TRUNCATE

·

Quickly remove all rows from a table.

-- TRUNCATE is faster than DELETE for removing all rows
-- TRUNCATE TABLE logs;

Tip: TRUNCATE is faster than DELETE but cannot be rolled back easily.

COPY

·

Bulk import/export data from files.

-- Import from CSV
-- COPY users FROM '/tmp/users.csv' WITH CSV HEADER;

-- Export to CSV
-- COPY (SELECT * FROM users) TO '/tmp/export.csv' WITH CSV HEADER;

Tip: Use \copy in psql for client-side file access.

Querying Data

SELECT

·

Retrieve data from one or more tables.

SELECT name, email FROM users;

SELECT *

·

Select all columns from a table.

SELECT * FROM products;

Tip: Avoid SELECT * in production; specify needed columns.

WHERE

·

Filter rows based on conditions.

SELECT * FROM orders WHERE price > 50 AND status = 'completed';

ORDER BY

·

Sort results by one or more columns.

SELECT * FROM products ORDER BY price DESC NULLS LAST;

Tip: PostgreSQL allows NULLS FIRST/LAST to control NULL ordering.

LIMIT & OFFSET

·

Limit the number of results and skip rows.

SELECT * FROM products ORDER BY price DESC LIMIT 3 OFFSET 1;

Tip: For large offsets, consider keyset pagination instead.

GROUP BY

·

Group rows by column values for aggregation.

SELECT status, COUNT(*) as count, SUM(price) as total
FROM orders GROUP BY status;

HAVING

·

Filter groups after GROUP BY (like WHERE for groups).

SELECT user_id, COUNT(*) as order_count
FROM orders
GROUP BY user_id
HAVING COUNT(*) > 1;

DISTINCT / DISTINCT ON

·

Return only unique values.

SELECT DISTINCT category FROM products;

-- First product per category (PostgreSQL-specific)
-- SELECT DISTINCT ON (category) * FROM products ORDER BY category, price;

Tip: DISTINCT ON is a PostgreSQL extension for getting first row per group.

INNER JOIN

·

Return rows where there is a match in both tables.

SELECT users.name, orders.product, orders.price
FROM orders
INNER JOIN users ON orders.user_id = users.id;

LEFT JOIN

·

Return all rows from left table, with matches from right.

SELECT users.name, orders.product
FROM users
LEFT JOIN orders ON users.id = orders.user_id;

Tip: Unmatched right table columns will be NULL.

Subquery

·

Use a query inside another query.

SELECT * FROM users
WHERE id IN (SELECT user_id FROM orders WHERE price > 100);

CTE (WITH clause)

·

Define a temporary named result set for the query.

WITH high_value_orders AS (
  SELECT user_id, SUM(price) as total
  FROM orders
  GROUP BY user_id
  HAVING SUM(price) > 100
)
SELECT users.name, high_value_orders.total
FROM high_value_orders
JOIN users ON users.id = high_value_orders.user_id;

Tip: CTEs make complex queries more readable.

UNION

·

Combine results from multiple SELECT statements.

SELECT name, 'user' as type FROM users
UNION ALL
SELECT name, 'product' as type FROM products;

Tip: UNION removes duplicates; UNION ALL keeps them.

Window Functions

·

Perform calculations across related rows.

SELECT name, price,
  ROW_NUMBER() OVER (ORDER BY price DESC) as rank,
  SUM(price) OVER () as total
FROM products;

Tip: Window functions don't collapse rows like GROUP BY.

Built-in Functions

COUNT

·

Count the number of rows.

SELECT COUNT(*) as total_orders FROM orders;

SUM & AVG

·

Calculate the sum or average of a column.

SELECT
  SUM(price) as total_revenue,
  AVG(price) as avg_order_value
FROM orders;

MIN & MAX

·

Find the minimum or maximum value.

SELECT MIN(price) as cheapest, MAX(price) as most_expensive
FROM products;

COALESCE

·

Return the first non-NULL value.

SELECT name, COALESCE(email, 'no email') as email
FROM users;

Tip: Useful for providing default values for NULL columns.

NULLIF

·

Return NULL if two values are equal.

SELECT name, NULLIF(stock, 0) as stock_or_null
FROM products;

Tip: Useful for avoiding division by zero: x / NULLIF(y, 0)

CASE

·

Conditional logic in SQL (like if/else).

SELECT product, price,
  CASE
    WHEN price > 500 THEN 'expensive'
    WHEN price > 100 THEN 'moderate'
    ELSE 'affordable'
  END as price_tier
FROM orders;

String Functions

·

Manipulate text values.

SELECT
  UPPER(name) as uppercase,
  LENGTH(name) as name_length,
  SPLIT_PART(email, '@', 1) as username
FROM users;

Date Functions

·

Work with dates and times.

SELECT
  NOW() as current_time,
  CURRENT_DATE as today,
  CURRENT_DATE + INTERVAL '7 days' as next_week,
  EXTRACT(YEAR FROM NOW()) as current_year;

JSON Functions

·

Extract and manipulate JSON data.

SELECT '{"name": "Alice", "age": 30}'::jsonb->>'name' as name;

Tip: Use JSONB over JSON for better performance and indexing.

Array Functions

·

Work with PostgreSQL arrays.

SELECT ARRAY[1, 2, 3] as arr,
  ARRAY[1, 2, 3] @> ARRAY[2] as contains_two,
  array_length(ARRAY[1, 2, 3], 1) as len;

Tip: Arrays can be indexed with GIN for fast lookups.

generate_series

·

Generate a series of values.

SELECT generate_series(1, 5) as num;

-- Date series
-- SELECT generate_series(
--   '2024-01-01'::date,
--   '2024-01-07'::date,
--   '1 day'::interval
-- ) as day;

Tip: Great for generating test data or filling date gaps.

Data Rules & Constraints

PRIMARY KEY

·

Uniquely identify each row in a table.

CREATE TABLE employees (
  id SERIAL PRIMARY KEY,
  name TEXT NOT NULL,
  department_id INTEGER
);

Tip: Use SERIAL, BIGSERIAL, or GENERATED ALWAYS AS IDENTITY.

FOREIGN KEY

·

Link to a row in another table.

CREATE TABLE orders (
  id SERIAL PRIMARY KEY,
  user_id INTEGER REFERENCES users(id) ON DELETE CASCADE
);

Tip: ON DELETE options: CASCADE, SET NULL, SET DEFAULT, RESTRICT.

UNIQUE

·

Ensure all values in a column are different.

CREATE TABLE users (
  id SERIAL PRIMARY KEY,
  email TEXT UNIQUE,
  username TEXT UNIQUE
);

NOT NULL

·

Prevent NULL values in a column.

CREATE TABLE products (
  id SERIAL PRIMARY KEY,
  name TEXT NOT NULL,
  price DECIMAL(10,2) NOT NULL
);

DEFAULT

·

Set a default value when none is provided.

CREATE TABLE logs (
  id SERIAL PRIMARY KEY,
  message TEXT,
  level TEXT DEFAULT 'info',
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CHECK

·

Validate data against a condition.

CREATE TABLE products (
  id SERIAL PRIMARY KEY,
  name TEXT NOT NULL,
  price DECIMAL CHECK (price > 0),
  stock INTEGER CHECK (stock >= 0)
);

EXCLUDE

·

Prevent overlapping values (PostgreSQL-specific).

-- Prevent overlapping date ranges
-- CREATE TABLE reservations (
--   room_id INTEGER,
--   during TSRANGE,
--   EXCLUDE USING gist (room_id WITH =, during WITH &&)
-- );

Tip: Requires btree_gist extension for non-range types.

Transactions

BEGIN

·

Start a new transaction.

BEGIN;

INSERT INTO users (name, email) VALUES ('Test', 'test@example.com');

-- Changes are not visible to other connections yet

Tip: PostgreSQL defaults to READ COMMITTED isolation.

COMMIT

·

Save all changes made in the transaction.

BEGIN;
INSERT INTO users (name, email) VALUES ('Test', 'test@example.com');
COMMIT;

SELECT * FROM users WHERE name = 'Test';

ROLLBACK

·

Undo all changes made in the transaction.

BEGIN;
DELETE FROM users;
ROLLBACK;

-- Users table is unchanged
SELECT * FROM users;

SAVEPOINT

·

Create a point to rollback to within a transaction.

BEGIN;
INSERT INTO users (name, email) VALUES ('A', 'a@test.com');
SAVEPOINT my_savepoint;
INSERT INTO users (name, email) VALUES ('B', 'b@test.com');
ROLLBACK TO SAVEPOINT my_savepoint;
COMMIT;

-- Only user 'A' was inserted
SELECT * FROM users WHERE email LIKE '%test.com';

LOCK / SELECT FOR UPDATE

·

Explicitly lock rows or tables.

-- Lock specific rows for update
-- SELECT * FROM orders WHERE id = 1 FOR UPDATE;

-- Skip already-locked rows (for queue processing)
-- SELECT * FROM jobs WHERE status = 'pending'
-- FOR UPDATE SKIP LOCKED LIMIT 1;

Tip: FOR UPDATE SKIP LOCKED is great for job queues.

Utilities & Advanced

Information Schema

·

Query database metadata.

SELECT table_name, column_name, data_type
FROM information_schema.columns
WHERE table_schema = 'public'
ORDER BY table_name, ordinal_position;

EXPLAIN ANALYZE

·

Show query execution plan with actual timing.

EXPLAIN ANALYZE
SELECT * FROM orders WHERE user_id = 1;

Tip: Use EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT) for more detail.

VACUUM

·

Reclaim storage and update statistics.

-- Update statistics for query planner
-- VACUUM ANALYZE users;

-- Reclaim space (locks table)
-- VACUUM FULL users;

Tip: VACUUM FULL locks the table; regular VACUUM does not.

pg_stat Views

·

Monitor database activity and performance.

-- See active queries
-- SELECT pid, state, query FROM pg_stat_activity;

-- Table statistics
-- SELECT relname, seq_scan, idx_scan FROM pg_stat_user_tables;

Extensions

·

Add extra functionality to PostgreSQL.

-- Enable UUID generation
-- CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

-- Enable full-text search
-- CREATE EXTENSION IF NOT EXISTS pg_trgm;

Tip: Popular: uuid-ossp, pgcrypto, pg_trgm, postgis.

LIKE & ILIKE

·

Pattern matching with wildcards.

SELECT * FROM users WHERE email ILIKE '%@example.com';

Tip: ILIKE is PostgreSQL-specific case-insensitive matching.

Regular Expressions

·

Match patterns using regex.

SELECT * FROM users WHERE email ~* '^[a-z]+@example\.com$';

Tip: PostgreSQL uses POSIX regex syntax.

LATERAL JOIN

·

Reference columns from preceding tables in subquery.

SELECT users.name, recent_order.product
FROM users
CROSS JOIN LATERAL (
  SELECT product FROM orders
  WHERE orders.user_id = users.id
  ORDER BY created_at DESC LIMIT 1
) recent_order;

Tip: LATERAL lets subqueries reference earlier table columns.

About This PostgreSQL Cheat Sheet

This PostgreSQL cheat sheet covers all the essential SQL commands you need for working with Postgres databases. Whether you're learning PostgreSQL for the first time or need a quick syntax reference, this guide has you covered.

Each PostgreSQL command includes a working example that you can copy or run directly in your browser. The interactive SQL editor lets you experiment with queries against sample data without installing anything.

PostgreSQL offers powerful features beyond standard SQL, including window functions, CTEs, JSON support, arrays, and advanced indexing. This cheat sheet covers both common SQL patterns and PostgreSQL-specific features.

Looking for more? Check out our PostgreSQL tutorials and guides for in-depth explanations, or try DB Pro for a visual way to explore and edit your PostgreSQL databases.