← Back to Index

PostgreSQL Reference

0. Connection & Basics

0.1 Client Connect

Connecting to a database via the psql CLI.

# Connect to 'mydb' as 'user' on 'localhost'
psql -h localhost -U user -d mydb

# Execute a single command and exit
psql -c "SELECT version();"
TERMINAL OUTPUT
PostgreSQL 16.1 on x86_64-pc-linux-gnu...

0.2 CLI Meta-commands

Internal psql commands for database introspection.

\l          -- List all databases
\c mydb     -- Connect to 'mydb'
\dt         -- List all tables in current schema
\d+ users   -- Describe table 'users' in detail
\i file.sql -- Execute commands from file.sql
\q          -- Quit psql
TERMINAL OUTPUT
(Introspection results)

0.3 Comments

Annotating SQL code.

-- Single-line comment

/* Multi-line
   comment block */
SELECT 1; -- Trailing comment
TERMINAL OUTPUT
 ?column? 
----------
        1

1. Data Types

1.1 Numerics

Standard and auto-incrementing types.

SELECT 
    42::SMALLINT,        -- 2-byte int
    100000::INTEGER,     -- 4-byte int
    10000000000::BIGINT, -- 8-byte int
    3.1415::NUMERIC(6,4),-- Exact decimal
    'NaN'::REAL;         -- 4-byte float
TERMINAL OUTPUT
 int2 |  int4  |    int8     | numeric | real 
------+--------+-------------+---------+------
   42 | 100000 | 10000000000 |  3.1415 |  NaN

1.2 Strings & Binaries

Text and raw byte storage.

SELECT 
    'fixed'::CHAR(5),       -- Padded string
    'var'::VARCHAR(10),     -- Limited string
    'unlimited'::TEXT,      -- Preferred for most text
    '\xDEADBEEF'::BYTEA;    -- Variable-length binary
TERMINAL OUTPUT
 char  | varchar |   text    |   bytea    
-------+---------+-----------+------------
 fixed | var     | unlimited | \xdeadbeef

1.3 Date & Time

Temporal types with timezone support.

SELECT 
    CURRENT_DATE,                             -- Date only
    CURRENT_TIME,                             -- Time with TZ
    NOW() AT TIME ZONE 'UTC',                 -- Timestamp without TZ
    INTERVAL '1 day 2 hours' AS duration;     -- Time span
TERMINAL OUTPUT
    date    |       time       |          timezone          |    duration    
------------+------------------+----------------------------+----------------
 2024-05-16 | 10:00:00.123+00  | 2024-05-16 10:00:00.123456 | 1 day 02:00:00

1.4 Booleans & Enums

Logical values and custom sets.

CREATE TYPE user_status AS ENUM ('active', 'banned');
SELECT 
    true::BOOLEAN AS is_ok,
    'active'::user_status;
TERMINAL OUTPUT
 is_ok | user_status 
-------+-------------
 t     | active

2. Basic Querying (DQL)

2.1 SELECT & Aliases

Retrieving and naming columns.

SELECT 
    first_name || ' ' || last_name AS full_name,
    UPPER(email) AS contact_email
FROM users;
TERMINAL OUTPUT
   full_name   |   contact_email   
---------------+-------------------
 Alice Johnson | ALICE@EXAMPLE.COM

2.2 WHERE Filtering

Conditional logic and pattern matching.

SELECT * FROM products
WHERE price > 100 
  AND category IN ('electronics', 'tools')
  AND name ~* '^pro.*'; -- Case-insensitive POSIX regex
TERMINAL OUTPUT
(Filtered rows)

2.3 ORDER BY

Sorting results.

SELECT name, price FROM products
ORDER BY category ASC, price DESC NULLS LAST;
TERMINAL OUTPUT
(Sorted rows)

2.4 LIMIT / OFFSET

Pagination.

SELECT id FROM events
ORDER BY created_at DESC
LIMIT 10 OFFSET 20; -- Skip first 20, take next 10
TERMINAL OUTPUT
(10 rows)

3. Joins & Set Operations

3.1 Inner & Outer Joins

Combining tables based on keys.

SELECT u.name, o.id
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE o.id IS NULL; -- Users with no orders
TERMINAL OUTPUT
(Users without orders)

3.2 Cross & Self Joins

Cartesian products and self-references.

-- Self join for hierarchical data
SELECT e.name AS emp, m.name AS manager
FROM employees e
JOIN employees m ON e.manager_id = m.id;
TERMINAL OUTPUT
(Pairs of employees and managers)

3.3 UNION, INTERSECT, EXCEPT

Combining result sets.

SELECT email FROM leads
UNION -- Removes duplicates (UNION ALL keeps them)
SELECT email FROM customers
EXCEPT
SELECT email FROM unsubscribed;
TERMINAL OUTPUT
(Distinct active emails)

3.4 JOIN with Subqueries

Using derived tables.

SELECT u.name, recent.max_date
FROM users u
JOIN (
    SELECT user_id, MAX(created_at) AS max_date 
    FROM logins GROUP BY user_id
) AS recent ON u.id = recent.user_id;
TERMINAL OUTPUT
(Users with their last login date)

4. Aggregation & Grouping

4.1 GROUP BY

Summarizing data by category.

SELECT category, COUNT(*), AVG(price)
FROM products
GROUP BY category;
TERMINAL OUTPUT
 category | count |        avg        
----------+-------+-------------------
 tools    |    15 | 42.50000000000000

4.2 HAVING

Filtering groups.

SELECT user_id, SUM(total)
FROM orders
GROUP BY user_id
HAVING SUM(total) > 1000;
TERMINAL OUTPUT
(High-value customers)

4.3 Aggregate Functions

Postgres-specific aggregates.

SELECT 
    COUNT(DISTINCT category) AS cats,
    STRING_AGG(name, ', ' ORDER BY name) AS all_names,
    ARRAY_AGG(id) AS id_list
FROM products;
TERMINAL OUTPUT
 cats |    all_names     |  id_list  
------+------------------+-----------
    5 | Drill, Saw, Wren | {10,12,5}

5. Advanced Querying

5.1 Subqueries (IN, EXISTS)

Correlated and non-correlated subqueries.

SELECT name FROM employees e
WHERE EXISTS (
    SELECT 1 FROM salaries s 
    WHERE s.emp_id = e.id AND s.amount > 100000
);
TERMINAL OUTPUT
(High earners)

5.2 Common Table Expressions (WITH)

Improving readability and reusability.

WITH regional_sales AS (
    SELECT region, SUM(amount) AS total FROM sales GROUP BY region
)
SELECT region FROM regional_sales 
WHERE total > (SELECT AVG(total) FROM regional_sales);
TERMINAL OUTPUT
(Above-average regions)

5.3 Recursive CTEs

Iterating over hierarchical or graph data.

WITH RECURSIVE subordinates AS (
    SELECT id, name, manager_id FROM employees WHERE id = 1
    UNION ALL
    SELECT e.id, e.name, e.manager_id 
    FROM employees e
    JOIN subordinates s ON e.manager_id = s.id
)
SELECT * FROM subordinates;
TERMINAL OUTPUT
(The entire management chain starting at ID 1)

6. Window Functions

6.1 OVER & PARTITION BY

Calculations across rows related to the current row.

SELECT 
    name, 
    price,
    AVG(price) OVER(PARTITION BY category) AS cat_avg
FROM products;
TERMINAL OUTPUT
(Product names, prices, and their category average)

6.2 Ranking

Assigning sequence numbers.

SELECT 
    name, 
    ROW_NUMBER() OVER(ORDER BY score DESC) AS pos,
    RANK() OVER(ORDER BY score DESC) AS rnk
FROM players;
TERMINAL OUTPUT
(Players ranked by score)

6.3 Analytics

Accessing other rows without joins.

SELECT 
    day, 
    value,
    LAG(value) OVER(ORDER BY day) AS prev_val,
    value - LAG(value) OVER(ORDER BY day) AS delta
FROM daily_stats;
TERMINAL OUTPUT
(Daily values and their change from previous day)

7. Data Modification (DML)

7.1 INSERT

Adding rows with RETURNING.

INSERT INTO users (name, email)
VALUES ('Bob', 'bob@example.com')
RETURNING id, created_at; -- Get generated values back immediately
TERMINAL OUTPUT
 id |          created_at           
----+-------------------------------
 42 | 2024-05-16 10:00:00.123456+00

7.2 UPDATE & DELETE

Modifying existing data.

UPDATE products SET price = price * 1.1 
WHERE category = 'luxury'
RETURNING name, price AS new_price;

DELETE FROM sessions WHERE last_seen < NOW() - INTERVAL '1 hour';
TERMINAL OUTPUT
(Affected rows)

7.3 Upsert / Merge

Handling conflicts during insert.

INSERT INTO user_prefs (user_id, theme)
VALUES (1, 'dark')
ON CONFLICT (user_id) 
DO UPDATE SET theme = EXCLUDED.theme, updated_at = NOW();
TERMINAL OUTPUT
INSERT 0 1

8. Schema Definition (DDL)

8.1 CREATE & ALTER Table

Defining and evolving structure.

CREATE TABLE items (
    id SERIAL PRIMARY KEY, -- Auto-incrementing 4-byte int
    uuid UUID DEFAULT gen_random_uuid(),
    metadata JSONB NOT NULL DEFAULT '{}'
);

ALTER TABLE items ADD COLUMN tags TEXT[] DEFAULT '{}';
TERMINAL OUTPUT
CREATE TABLE

8.2 Constraints

Ensuring data integrity.

CREATE TABLE accounts (
    id INT PRIMARY KEY,
    email TEXT UNIQUE NOT NULL CHECK (email ~* '@'),
    balance NUMERIC DEFAULT 0 CHECK (balance >= 0),
    parent_id INT REFERENCES accounts(id) ON DELETE CASCADE
);
TERMINAL OUTPUT
CREATE TABLE

8.3 Indexes & Performance

Optimizing queries.

CREATE INDEX idx_user_email ON users (email);
CREATE INDEX idx_item_meta ON items USING GIN (metadata); -- GIN for JSONB
TERMINAL OUTPUT
CREATE INDEX

8.4 Views & Materialized Views

Stored queries and cached results.

CREATE VIEW active_users AS SELECT * FROM users WHERE status = 'active';

-- Materialized view requires manual refresh
CREATE MATERIALIZED VIEW sales_summary AS 
SELECT region, SUM(amount) FROM sales GROUP BY region;

REFRESH MATERIALIZED VIEW sales_summary;
TERMINAL OUTPUT
REFRESH MATERIALIZED VIEW

9. Logic & Administration

9.1 Transactions (ACID)

Ensuring atomic operations.

BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT; -- Or ROLLBACK on error
TERMINAL OUTPUT
COMMIT

9.2 Triggers & Functions

Server-side logic.

CREATE FUNCTION update_timestamp() RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = NOW();
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_update_items 
BEFORE UPDATE ON items 
FOR EACH ROW EXECUTE FUNCTION update_timestamp();
TERMINAL OUTPUT
CREATE TRIGGER

9.3 Explain Plan & Optimization

Analyzing query execution.

EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM orders WHERE user_id = 500;
TERMINAL OUTPUT
 Index Scan using idx_orders_user_id on orders...
 Execution Time: 0.042 ms

9.4 Roles, Permissions & Schemas

Security and organization.

CREATE ROLE read_only;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only;

CREATE SCHEMA archive;
ALTER TABLE old_logs SET SCHEMA archive;
TERMINAL OUTPUT
ALTER TABLE