Scenario: Brightlane's fulfillment operations team is sizing daily staffing against last year's order volume and needs a complete view of the first week of January 2024.
Task: Write a query to return each date from January 1, 2024 through January 7, 2024 alongside the number of orders placed on that date.
Assumptions:
- The
orderstable holds one row per placed order, with the placement timestamp stored inordered_at. - Some dates in the range have no recorded
orders; those dates must still appear in the result with a count of zero.
Output:
- One row per date in the range, including dates with no
orders. - Columns in this order:
day,order_count. - Sorted by
dayascending.
Schema · ecommerce 5 tables
Run previews · Check grades
Write a query, then run it to see results here.
Worked solution Try it yourself first
WITH
spine AS (
SELECT
GENERATE_SERIES('2024-01-01'::date, '2024-01-07'::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
The seven-day range has to be present in the result even on days with zero orders, so the spine generates every date in the range and the orders table is left-joined onto it. The structural rows come from the spine, not from the fact data.
Clause by clause
WITH spine AS (SELECT generate_series('2024-01-01'::date, '2024-01-07'::date, '1 day'::interval)::date AS day)builds the seven-row backbone — one row for each calendar day from January 1 through January 7. The outer::datecast strips the timestamp produced bygenerate_seriesback to a plain date so the join key lines up cleanly.SELECT s.day, COUNT(o.id) AS order_countreturns the spine's date and the count of matched orders for that date.COUNT(o.id)counts non-nullidvalues, so unmatched spine rows contribute zero rather than one.FROM spine s LEFT JOIN orders o ON o.ordered_at::date = s.dayattaches each placed order to its day. TheLEFT JOINkeeps every spine row even when noordersmatch; that's what produces the zero rows for January 1 through 4, 6, and 7.GROUP BY s.daycollapses the joined rows back to one row per spine date. The grouping key is the spine column, not the fact column, which is what guarantees one output row per generated date.ORDER BY s.dayreturns the seven dates in calendar order.
The trap
Joining orders to the spine instead of the spine to orders looks identical at a glance but produces a completely different result. An INNER JOIN or a fact-table-first join drops spine rows that have no matching orders — exactly the rows the pattern exists to keep. The spine has to be the left table.
You practiced anchoring the result to a generated date spine with a left-join so that quiet days appear with a count of zero instead of dropping out.