CTE and Subquery Tradeoffs
Interviewers evaluate reasoning quality, not just syntax. This lesson helps you justify CTE vs subquery decisions.
Decision Framework #
Use CTEs when:
- you need step-wise logic clarity
- multiple downstream references improve readability
- debugging intermediate outputs matters
Use subqueries when:
- logic is simple and local
- a one-off nested operation is sufficient
- extra named steps add noise
Prompt #
Return customers whose monthly spend is above their average for the prior 3 months (excluding current month).
Honest caveat to state in the interview: ROWS BETWEEN 3 PRECEDING AND 1 PRECEDING averages the customer's prior three active months, not the prior three calendar months. When a customer skips a month, the window silently reaches further back in time. If the requirement is strictly calendar-based, densify first with a month spine (cross join customers to a generated month series, defaulting missing months to 0) so every calendar month is present before applying the window.
Validation Check #
-- First month per customer should have no prior-window average
WITH monthly AS (
SELECT
customer_id,
DATE_TRUNC('month', order_date) AS month_start,
SUM(order_total) AS monthly_spend
FROM ecom_orders
WHERE order_status = 'completed'
GROUP BY customer_id, DATE_TRUNC('month', order_date)
),
windowed AS (
SELECT
customer_id,
month_start,
AVG(monthly_spend) OVER (
PARTITION BY customer_id
ORDER BY month_start
ROWS BETWEEN 3 PRECEDING AND 1 PRECEDING
) AS prior_3m_avg
FROM monthly
)
SELECT *
FROM windowed
WHERE prior_3m_avg IS NOT NULL
AND month_start = (
SELECT MIN(m2.month_start)
FROM monthly m2
WHERE m2.customer_id = windowed.customer_id
);Scoring Rubric #
- correctness of prior-window logic (40%)
- clarity of CTE vs subquery tradeoff reasoning (25%)
- validation quality (20%)
- communication and assumptions (15%)
A clear, correct query with explicit tradeoffs beats an over-optimized but opaque answer.