CoreTrail

PostgreSQL toolkit

Work with arrays, JSON, views, and database routines.

Chapter overviewPostgreSQL5 min read
On this page

Use PostgreSQL features with explicit grain

Arrays, JSONB, lateral expansion, and DISTINCT ON are useful extensions of ordinary relational patterns. Expansion can multiply rows; aggregation can collect them again. Keep track of those transitions.

Suggested route: Start from the quick reference, then run the arrays and JSON examples with empty and null inputs. Connect views and routines to their lifecycle and access rules.

By the end: Explain when a PostgreSQL-specific construct improves clarity and what must change in another dialect.

Quick reference

PostgreSQL syntax Use when Common combination
FILTER (WHERE ...) Conditional aggregate COUNT, SUM, AVG
DISTINCT ON (...) Pick first row per key ordered latest/earliest row
GENERATE_SERIES Generate rows calendar spines
STRING_AGG Ordered grouped string DISTINCT, ORDER BY
ARRAY_AGG Collect group values DISTINCT, ORDER BY
UNNEST Expand arrays to rows LATERAL
WITH ORDINALITY Keep array/function element position UNNEST
LATERAL Right-side expression depends on left row per-row top N, expansion
ANY(array) Test array membership/comparison = ANY(array)
jsonb -> / ->> Extract JSON value nested fields
jsonb_array_elements Expand JSON arrays LATERAL
ON CONFLICT PostgreSQL upsert unique constraints
RETURNING Return changed rows INSERT/UPDATE/DELETE
::type PostgreSQL cast shorthand dates / numeric conversion
ILIKE Case-insensitive LIKE text search
materialized view Persist query result expensive reusable reads

DISTINCT ON

Latest row per customer:

SELECT DISTINCT ON (customer_id)
       customer_id, order_id, order_ts
FROM orders
ORDER BY customer_id, order_ts DESC, order_id DESC;

The ORDER BY chooses which row survives. For portable SQL, use ROW_NUMBER().

Arrays: expand and preserve position

SELECT u.user_id, x.skill, x.position
FROM user_skills u
CROSS JOIN LATERAL
     UNNEST(u.skills) WITH ORDINALITY AS x(skill, position);

Use LEFT JOIN LATERAL ... ON TRUE when users with null/empty expansions must remain.

Membership without expansion:

WHERE 'SQL' = ANY(skills)

JSONB: extract vs expand

payload -> 'user'         -- JSON/JSONB value
payload ->> 'user_id'     -- text value

Use expansion functions when one JSON array element should become one SQL row. Expansion changes grain, so check row multiplication just as you would with a join.

Upsert and changed-row output

INSERT INTO users(user_id, name)
VALUES (1, 'Kayvan')
ON CONFLICT (user_id)
DO UPDATE SET name = EXCLUDED.name
RETURNING *;

ON CONFLICT relies on an applicable unique/exclusion constraint. RETURNING is useful when the caller needs generated IDs or the final stored row.

High-value PostgreSQL combinations

GENERATE_SERIES + LEFT JOIN
    missing-date/calendar reports

UNNEST + WITH ORDINALITY
    expand while keeping original array order

LEFT JOIN LATERAL + ORDER BY + LIMIT
    latest/top-N related rows while preserving parents

FILTER + aggregate
    concise conditional metrics

DISTINCT ON + ORDER BY
    PostgreSQL-specific latest/earliest record

JSONB expansion + LATERAL
    nested repeated data → relational rows

Common traps

  • Two independent UNNEST/expansion operations can multiply row counts.
  • DISTINCT ON without deterministic ORDER BY can choose an unintended survivor.
  • -> returns JSON; ->> returns text.
  • ON CONFLICT is not a substitute for deciding the correct uniqueness key.
  • PostgreSQL-specific shortcuts are useful in interviews only when the dialect permits them.

In this chapter

How to study

Treat this page as a dialect toolbox. Know which constructs are PostgreSQL-specific and be ready to give the portable alternative where one exists.

Type a concept, keyword, or function.