Scenario: Brightlane's CFO requires a quarterly business review summarizing order activity for each fiscal quarter.
Task: Write a query to return each calendar quarter, the number of orders placed in that quarter, the total orders revenue, and the average value per order.
Assumptions:
- The
orderstable holds one row per placed order, with the placement timestamp stored inordered_atand the order amount stored intotal_amount. - A calendar quarter is identified by its first day and covers every order placed within that quarter.
Output:
- One row per calendar quarter present in the data.
- Columns in this order:
quarter_start(the first day of the calendar quarter),order_count,total_revenue,avg_order_value.
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
DATE_TRUNC('quarter', ordered_at)::date AS quarter_start,
COUNT(*) AS order_count,
SUM(total_amount) AS total_revenue,
AVG(total_amount) AS avg_order_value
FROM
orders
GROUP BY
DATE_TRUNC('quarter', ordered_at) The shape
date_trunc('quarter', ordered_at) collapses every order timestamp down to the first day of its calendar quarter, so all orders placed in Q1, Q2, Q3, or Q4 of a given year share a single grouping key. Three aggregates then run side by side on each quarter's rows: COUNT for the order volume, SUM for the total revenue, and AVG for the per-order average.
Clause by clause
SELECT date_trunc('quarter', ordered_at)::date AS quarter_start, COUNT(*) AS order_count, SUM(total_amount) AS total_revenue, AVG(total_amount) AS avg_order_valuereturns one row per quarter with four columns. The::datecast normalises the truncated timestamp to a plain date. The three aggregates are independent:SUMadds the dollars,COUNTcounts the orders,AVGaverages the dollars across the same set of rows.FROM ordersreads every placed order. There is noWHERE; the CFO's quarterly review covers every quarter in the data.GROUP BY date_trunc('quarter', ordered_at)repeats the truncation as the grouping key. An order from January and an order from March of the same year both truncate to that year's January 1 and land in the same Q1 group.
The trap
date_trunc('quarter', ...) snaps to the first day of the calendar quarter (January 1, April 1, July 1, October 1), not to the first day of a fiscal quarter offset from the calendar. If Brightlane's fiscal year started in a month other than January, the 'quarter' field would still produce calendar-quarter buckets, and the totals would not line up with what the finance team expects on the fiscal report. The prompt says calendar quarter, so calendar-quarter truncation is correct here. Any change to a fiscal definition requires date arithmetic to shift the timestamp before truncation, not a different field name on date_trunc.
You practiced reporting per-quarter totals by truncating timestamps with date_trunc('quarter', ...), so every order in a quarter collapses into a single row.