Brightlane's retention team wants to understand the experience new customers had on their very first order.
Write a query to return every order's ID, customer ID, status, and the status of that same customer's first order chronologically.
Assumptions:
- The
orderstable has one row per order with anid, acustomer_id, astatus, and anordered_attimestamp. - A customer's first order is the order with the smallest
ordered_atfor thatcustomer_id. The same first-order status appears on every row sharing acustomer_id. - The final result is sorted by
customer_idascending, then byordered_atascending.
Output:
- One row per order, with columns
id,customer_id,status, andfirst_order_status. Sorted bycustomer_id, thenordered_at.
Schema · ecommerce 5 tables
Run previews · Check grades
Write a query, then run it to see results here.
Worked solution Try it yourself first
SELECT
id,
customer_id,
status,
FIRST_VALUE(status) OVER (
PARTITION BY
customer_id
ORDER BY
ordered_at
) AS first_order_status
FROM
orders
ORDER BY
customer_id,
ordered_at The shape
FIRST_VALUE works on any column type, not just numerics. FIRST_VALUE(status) returns the text value that sits at position 1 of the ordered partition and copies it onto every row sharing that customer_id. Each order ends up annotated with the status the same customer's first order ended in.
Clause by clause
SELECT id, customer_id, status, FIRST_VALUE(status) OVER (PARTITION BY customer_id ORDER BY ordered_at) AS first_order_statusreturns each order's identifying columns plus the status of that customer's first order. The window'sPARTITION BY customer_idgroups the customer's orders together;ORDER BY ordered_atsequences them chronologically;FIRST_VALUEpulls back the value at position 1.FROM ordersreads every order.ORDER BY customer_id, ordered_atsorts the printed output chronologically within each customer.
The trap
The expression being passed to FIRST_VALUE decides the result type. FIRST_VALUE(status) returns text because status is text; FIRST_VALUE(total_amount) would return numeric. The function does not coerce, summarise, or aggregate the value at position 1; it returns it exactly as stored. Any analytic operation that needs a non-text first value has to be applied either before the lookup (transform the column inside the function call) or after (transform the returned value in the outer query).
You practiced FIRST_VALUE over a non-numeric column — the function returns whatever type sits at the first position, including text values.