runtime
40 / 88

lesson 40 Window functions · advanced

Latest row per group

Keep the most recent record for each group.

the idea

Use a CTE with ROW_NUMBER sorted newest-first, then filter to row number 1. A window result cannot be filtered by WHERE in the same query block.

tables in this lesson

The challenges use this data. Each column shows its type underneath; → marks a link to another table.

orders6 columns · 12 rows
idinteger · keycustomer_idintegerproduct_idintegerquantityintegerstatustextordered_attext
101112paid2025-01-01
102231paid2025-01-02
103121paid2025-01-05
104352pending2025-01-08
105445paid2025-02-01

showing 5 of 12 rows

products4 columns · 6 rows
idinteger · keynametextcategorytextpricereal
1NotebookStationery12
2Desk lampHome45
3KeyboardTech80
4Pen setStationery8
5HeadphonesTech120

showing 5 of 6 rows

example

The idea in one query. Press Run to see what it returns; running examples never affects your progress.

example.sql
WITH ranked AS (
  SELECT
    *,
    ROW_NUMBER() OVER(PARTITION BY customer_id ORDER BY ordered_at DESC,id DESC) AS rn
  FROM orders
)
SELECT id,customer_id,ordered_at
FROM ranked
WHERE rn=1;

Watch for: MAX(date) plus an unrelated id does not reliably select the entire latest row.

build it step by step

Each step changes one thing. Run them in order and watch the result change.

  1. See multiple rows per customer. Customers can have several orders. Choosing the latest one needs an order and a way to keep only rank 1.

    step-1.sql
    SELECT id, customer_id, ordered_at
    FROM orders
    ORDER BY customer_id, ordered_at DESC, id DESC
    LIMIT 12;
  2. Keep the newest row per group. ROW_NUMBER ordered by newest first marks the latest order as 1. Filtering rn = 1 keeps one row per customer.

    step-2.sql
    WITH ranked AS (
      SELECT
        *,
        ROW_NUMBER() OVER( PARTITION BY customer_id ORDER BY ordered_at DESC, id DESC ) AS rn
      FROM orders
    )
    SELECT id, customer_id, ordered_at
    FROM ranked
    WHERE rn = 1;

challenge 1

Return id, customer_id and ordered_at for the latest order per customer; break date ties by highest id.

Return idcustomer_idordered_atany row order

challenge-1.sql
 
To master this lesson, solve both challenges without hints and pass the concept check. 3 of 3 to go.