Calculate a Running Median of Order Totals
Return each order with the median total of all orders placed up to and including its date.
The challenge runs on the SQLabHub practice database (SQLite) and uses the orders table. You can solve it in the browser, with nothing to install.
The task
For each order, calculate the running median: the median total of all orders placed up to and including that order date.
A correct answer returns 200 rows with 4 columns: id, order_date, total, running_median.
Tables used in this challenge
orders 200 rows
id INTEGER (PK) · user_id INTEGER · total REAL · discount REAL · item_count INTEGER · status TEXT · order_date TEXT · shipped_date TEXT · shipping_city TEXT · shipping_country TEXT
| id | user_id | total | discount | item_count | status | order_date | shipped_date | shipping_city | shipping_country |
|---|---|---|---|---|---|---|---|---|---|
The first rows of each table are shown. See how all the tables relate on the database schema page.
Expected output
| id | order_date | total | running_median |
|---|---|---|---|
First 5 of 200 rows. This is the output of the model solution on the practice database.
What you practise
- Filtering rows with a WHERE condition
- Summarising many rows into one value with COUNT, SUM, AVG, MIN or MAX
- Writing a subquery that refers to the current row of the outer query
- Querying the result of another query with a subquery in FROM
- Numbering rows with ROW_NUMBER() to pick one or a few per group
- Attaching a total or average to every row with an aggregate OVER ()
- Sorting the result with ORDER BY
Hint and approach
Try the challenge first. Open these only when you need them.
Show the hint
Use a correlated subquery that computes the median of the earlier orders with ROW_NUMBER and COUNT
Show the step-by-step approach
How the model solution is built, in the order the database evaluates it:
- Read from the
orderstable. - Number the rows with
ROW_NUMBER(), ordered bytotal. - Compute
COUNT(*)with an emptyOVER (), so the figure for the whole result is repeated on every row. - A subquery in the SELECT list is evaluated for each output row, using values from that row:
- Build an inner query first (a derived table):
- Read from the
orderstable. - Filter in
WHERE: keep the rows whereorder_dateis at most the outer row'sorder_date. - Number the rows with
ROW_NUMBER(), ordered bytotal. - Compute
COUNT(*)with an emptyOVER (), so the figure for the whole result is repeated on every row.
- Read from the
- Filter in
WHERE: keep the rows wherernis one of(cnt + 1) / 2or(cnt + 2) / 2. The filter sits in the outer query because a window function cannot be tested in the WHERE clause of the query that computes it. - Aggregate over all the rows that are left: compute
AVG(total). With no GROUP BY, the result is a single row.
- Build an inner query first (a derived table):
- Sort the result by
order_date.
Model solution
Checking your session…
What to watch for
SQLite has no MEDIAN and no window frame that can produce one, so each row gets a correlated subquery that ranks the earlier orders and averages the middle one or two. That is quadratic work: fine for 200 orders, slow for a large table. Orders on the same date share one median, because the cutoff is the date.
- Correlated subquery. A correlated subquery is evaluated per outer row, which gets slow on large tables. A join to a grouped subquery or a window function usually does the same work in one pass.
- ROW_NUMBER(). ROW_NUMBER() breaks ties arbitrarily. When the ORDER BY inside OVER does not identify one row, the row that gets number 1 can change between runs.
- Window aggregates. A window aggregate keeps every row, while a plain aggregate collapses them. Mixing the two in one SELECT without GROUP BY is an error.
Related SQL challenges
- Calculate the Median Salary Without a MEDIAN FunctionSimilar levelHard
- Calculate the Median Salary per DepartmentSimilar levelHard
- Find the Amount of Each Customer's Most Recent OrderEasierMedium
- Find Each Customer's Largest OrderSimilar levelHard
- Find Each Customer's First OrderSimilar levelHard
Keep learning
- Lesson: Correlated Subqueries
- Lesson: ROW_NUMBER()
- Lesson: Window Functions
- Lesson: SQL Subqueries
- All SQL practice challenges, by difficulty and topic
- SQL interview questions with answers
- SQL Playground: run any query on the same database