SQL theory · page 6 of 10

Views, CTEs and window functions

Saved queries, named steps, and calculations over related rows.

Real analysis takes several steps. SQL has three tools to keep them readable: views, CTEs and window functions.

Views

A view is a saved query with a name, used like a table. It stores no data: each time it is queried, its query runs. Define a business measure once, such as earned premium, and every report that uses the view agrees. A materialised view stores its result, and is brought up to date with refresh materialized VIEW: fast to read, but only as fresh as its last refresh.

Common table expressions

A CTE is a named step inside one query, written with WITH. Each step can use the ones before it, so a long query reads top to bottom, like a recipe. Since PostgreSQL 12 a CTE is usually folded into the main query, so it costs nothing extra.

WITH open_claims AS (
    SELECT * FROM claims WHERE status = 'open'
),
by_cause AS (
    SELECT cause, COUNT(*) AS claims, SUM(reserve) AS reserves
    FROM open_claims
    GROUP BY cause
)
SELECT * FROM by_cause
ORDER BY reserves DESC;
Two named steps, then the result. Try it in the playground

Window functions

An aggregate with GROUP BY collapses rows into one per group. A window function computes over related rows but keeps every row: each claim with the total of its policy, or each payment with the running total so far. OVER (...) defines the window:

  • PARTITION BY: the groups, like GROUP BY, but without collapsing them.
  • ORDER BY: the order within each partition, for rankings, running totals and LAG.
  • A frame, such as ROWS BETWEEN 2 preceding AND current ROW: which rows around the current one count.
FunctionGivesTies (equal values)
ROW_NUMBER()1, 2, 3, 4numbered arbitrarily
RANK()1, 2, 2, 4share a rank, then a gap
DENSE_RANK()1, 2, 2, 3share a rank, no gap
LAG(x), LEAD(x)x from the previous or next row
SUM(x) OVER (ORDER BY ...)a running totaltied rows are added together
With ORDER BY and no frame, the window runs to the current row and its ties. For a running total that grows one row at a time, order by something unique, such as the date and then the id.
SELECT claim_id, paid_on, amount,
       SUM(amount) OVER (PARTITION BY claim_id ORDER BY paid_on, payment_id) AS paid_so_far
FROM claim_payments
ORDER BY claim_id, paid_on
LIMIT 10;
Each payment, with the total paid on its claim up to then. Try it in the playground
Practise it on Day 6

Check your understanding

Answer every question, then check.

1. What does a (non-materialised) view store?

2. Three claims tie for second place. What does RANK() give the next claim?

3. How does a window function differ from GROUP BY?

An unhandled error has occurred. Reload 🗙

Reconnecting…

Your connection to Data Analytics SQL Lab dropped, probably a Wi-Fi blip. Hold on while it reconnects. Your work is kept.

The connection could not be restored. The page will reload in a few seconds.