N027-M3 Tier 2 · Core SQL · medium ecommerce · Brightlane

Return both averages in a single row

Part of Conditional Aggregation (CASE inside Aggregates) in SQL

The problem

Brightlane's inventory team wants a single-row price comparison:

  • Average price of in-stock products (stock_qty > 0).
  • Average price of out-of-stock products (stock_qty = 0).

Write a query to return both averages in a single row.

Assumptions:

  • The products table contains every product in the catalogue.
  • Each AVG(CASE ...) computes the average over only the rows that match the condition — the unmatched rows return NULL from CASE and AVG ignores NULL in both the numerator and denominator.

Output:

  • A single row with two columns, avg_instock_price and avg_outofstock_price.
Schema · ecommerce 5 tables
categories
id integer
name text
parent_id? integer
products
id integer
name text
category_id integer
price numeric
stock_qty integer
attributes? jsonb
order_items
id integer
order_id integer
product_id integer
quantity integer
unit_price numeric
customers
id integer
name text
email text
city? text
country text
created_at timestamptz
is_active boolean
orders
id integer
customer_id integer
ordered_at timestamptz
status text
total_amount numeric

Run previews · Check grades

Write a query, then run it to see results here.

Worked solution Try it yourself first
Solution query
SELECT
  AVG(
    CASE
      WHEN stock_qty > 0 THEN price
    END
  ) AS avg_instock_price,
  AVG(
    CASE
      WHEN stock_qty = 0 THEN price
    END
  ) AS avg_outofstock_price
FROM
  products

The shape

AVG(CASE WHEN cond THEN price END) returns the average price over only the rows where cond is true. The out-of-stock average comes back as NULL because Brightlane has no products with stock_qty = 0 in the catalogue right now — the CASE returned NULL for every row, and AVG over an empty set is itself NULL.

Clause by clause

  • AVG(CASE WHEN stock_qty > 0 THEN price END) AS avg_instock_price evaluates the CASE once per product. Where stock_qty is greater than 0, the CASE returns that product's price; otherwise it falls through with no ELSE and returns NULL. AVG skips the NULLs on both sides of the division — they are not added to the sum, and they are not counted in the denominator — so the result is the average price across the in-stock subset, 326.58....
  • AVG(CASE WHEN stock_qty = 0 THEN price END) AS avg_outofstock_price does the same against the opposite predicate. Every row falls through to NULL, the input set for AVG is empty, and the result is NULL. Not 00 would mean "I averaged some prices and the answer was zero," which is a different claim. NULL means "there was nothing to average."
  • FROM products is the source set. The query is not grouped: the two averages are computed across the whole catalogue in a single pass, with the CASE doing the per-row routing into the right bucket.

Why this and not SUM / COUNT manually

A hand-rolled SUM(CASE) / COUNT(CASE) produces the same number when there's data to average, but it has two failure modes AVG avoids. On an empty input set, the manual division is zero divided by zero, which raises a division-by-zero error rather than returning NULL. And on an integer column, SUM / COUNT runs integer division and truncates the fractional part — the N013-H2 trap that AVG's automatic type-widening sidesteps.

You practiced AVG(CASE) for conditional averaging. The recurring rule: AVG excludes NULL from both the sum and the count, so an AVG(CASE WHEN cond THEN col END) is exactly the average of col over the rows where cond is true — as if the other rows didn't exist.

How you actually get good at SQL

Reading explains SQL. Writing it, over and over with instant feedback, is what makes you fluent.

That's the whole SQLMaxx loop: 600+ real problems, instant AI feedback, mastery you can actually see, and spaced review that won't let you forget.

A stack of SQL practice problem cards, the top card showing an employees table.
615 problems · 66 concepts

Real problems. Not toy examples.

615 hand-built problems spanning all 66 concepts, from basic SELECTs to window functions, built on real schemas and real business questions, the kind you'll actually get asked on the job. Enough reps to make SQL automatic.

A retro computer showing a SQL query marked correct with a green checkmark.
Instant AI feedback

Write a query. Know if it's right in one second.

No copying an answer and hoping it clicked. The AI grader checks your real query against real data, catches exactly what's wrong, and explains the fix in plain English, like a senior analyst reading over your shoulder on every problem.

A circular mastery progress dial filling from blue to green, the SQLMaxx diamond at its center.
Mastery tracking

Stop guessing whether you actually know it.

SQLMaxx tracks every concept and shows you what you've mastered and what's still shaky. Your skills fill in one concept at a time, so 'I think I get joins' becomes something you can prove.

A SQL query editor circled by a blue return arrow with a clock, scheduled to come back for review.
Spaced review

Learn it once. Keep it for good.

Most of what you learn this week fades by next week. So when a concept comes due for review, SQLMaxx hands you a fresh problem to solve from a blank editor, not a flashcard to re-read. A research-backed spaced-repetition algorithm (FSRS) times each return for right before you'd forget, so your SQL is still there months later, when the interview or the job actually needs it.

Practice, feedback, mastery, review. That's the loop that turns reading into real skill.

Start free

No account, no credit card. Start solving in under a minute.