N055-H1 Tier 4 · Advanced · hard ecommerce · Brightlane

Return each date in the series — starting on March 15, 2024 and ending on March 1, 2024 — alongside the number of `orders` placed on that date

Part of Date Spine Construction and Zero-Fill Patterns in SQL

The problem

Scenario: Brightlane's data pipeline runs a date-spine validation step before publishing reports. A configuration error has reversed the parameters so the run is asked to build a daily series starting on March 15, 2024 and ending on March 1, 2024.

Task: Write a query to return each date in the series — starting on March 15, 2024 and ending on March 1, 2024 — alongside the number of orders placed on that date.

Assumptions:

  • The orders table holds one row per placed order, with the placement timestamp stored in ordered_at.
  • The series starts on March 15, 2024 and ends on March 1, 2024. Because the start date falls after the end date, no calendar dates fall within the series; the result is empty.

Output:

  • One row per date in the series. The series contains no dates, so the result is empty.
  • Columns in this order: day, order_count.
  • Sorted by day ascending.
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
WITH
  spine AS (
    SELECT
      GENERATE_SERIES('2024-03-15'::date, '2024-03-01'::date, '1 day'::INTERVAL)::date AS DAY
  )
SELECT
  s.day,
  COUNT(o.id) AS order_count
FROM
  spine s
  LEFT JOIN orders o ON o.ordered_at::date = s.day
GROUP BY
  s.day
ORDER BY
  s.day

The shape

generate_series walks from the start argument toward the end argument by the step argument. When the step is positive and the start is later than the end, the very first step already overshoots the end and the generator stops without producing a single row. The spine is empty, so the surrounding query has nothing to join to and returns nothing.

Clause by clause

  • WITH spine AS (SELECT generate_series('2024-03-15'::date, '2024-03-01'::date, '1 day'::interval)::date AS day) asks the generator to step forward by one day from March 15 toward March 1. Forward from March 15 is March 16, March 17, and so on — never March 1. The first comparison against the end value already fails, so zero rows are produced.
  • SELECT s.day, COUNT(o.id) AS order_count describes the per-day output shape. With no spine rows to drive the result, SELECT has no input rows to evaluate.
  • FROM spine s LEFT JOIN orders o ON o.ordered_at::date = s.day attaches each order to its day. A LEFT JOIN from an empty left table is itself empty — a LEFT JOIN keeps every left-side row, and there are no left-side rows to keep.
  • GROUP BY s.day would collapse the joined rows back to one row per spine date. With no joined rows, it produces no groups.
  • ORDER BY s.day would sort the result. With no result, sorting is a no-op.

Why this and not "swap the arguments to fix it"

A pipeline that received a reversed range may have done so deliberately — for instance, to signal an invalid configuration that should produce no output rather than be quietly corrected. Silently swapping the bounds would mask the upstream configuration error. The right behavior for the pure spine query is to let the empty series propagate; whatever is calling this query gets to decide whether an empty result means "no activity" or "bad input."

The trap

generate_series does not raise an error on a reversed range. It returns zero rows, the LEFT JOIN returns zero rows, and the final query returns zero rows — all without a single warning. A pipeline that consumes this output sees an empty result and may interpret it as "no orders that week," which is the wrong reading. Any time a date spine produces an empty result, check the order of the start and end arguments before checking the fact data.

You practiced reasoning about a date spine whose start follows its end — the generator produces an empty series, so the surrounding query returns no results.

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.