Interview Prep

SQL Scenario Questions for Data Analyst Interviews

9 min read · Updated August 28, 2026

Data analyst interviews rarely ask "what does GROUP BY do". They hand you a business question and watch you turn it into a query — including the part where you notice the question is ambiguous. The ten scenarios below are written against this site's own sample database (Departments, Employees, Customers, Products, Orders), so every solution genuinely runs: read the ask, write your own query in the playground first, then open the solution and compare.

Scenario 1: How much revenue have we actually shipped?

Finance wants one number: the total order_total of orders whose status is Shipped — not pending, not cancelled, shipped.

Show the solution
SELECT SUM(order_total) AS shipped_revenue
FROM Orders
WHERE status = 'Shipped';

One aggregate, one filter. The interview point is noticing that “revenue” is ambiguous until you pin down which statuses count — a good analyst asks that question out loud before writing the query.

Scenario 2: What are our three best-selling products by revenue?

Marketing wants the top three products by total order value, ignoring cancelled orders.

Show the solution
SELECT p.name, SUM(o.order_total) AS revenue
FROM Orders o
JOIN Products p ON p.product_id = o.product_id
WHERE o.status <> 'Cancelled'
GROUP BY p.name
ORDER BY revenue DESC
LIMIT 3;

Join to get the product name, WHERE before grouping so cancelled orders never enter the totals, then sort and cut. Putting the status filter in HAVING instead would work here but describes the wrong intent — the rows should be excluded before summing, not after.

Scenario 3: Do bigger customers place bigger orders?

Compare customer tiers: for each tier, how many orders were placed and what was the average order value?

Show the solution
SELECT c.tier, COUNT(*) AS orders, AVG(o.order_total) AS avg_order_value
FROM Orders o
JOIN Customers c ON c.customer_id = o.customer_id
GROUP BY c.tier
ORDER BY avg_order_value DESC;

A join plus GROUP BY on the joined column. Note that AVG is per order, not per customer — if the interviewer wants average per customer, that is a different query with a subquery or two GROUP BYs, and spotting that ambiguity scores points.

Scenario 4: Which employees have never handled an order?

HR is reviewing sales coverage. List employees with no orders at all.

Show the solution
SELECT e.first_name, e.last_name
FROM Employees e
LEFT JOIN Orders o ON o.emp_id = e.emp_id
WHERE o.order_id IS NULL
ORDER BY e.first_name;

The anti-join pattern: LEFT JOIN keeps every employee, and the unmatched ones carry NULL in the right-hand columns — filtering on that NULL keeps exactly the employees with no match. NOT IN and NOT EXISTS answer it too; NOT IN needs care around NULLs.

Scenario 5: How does order volume move month to month?

Build the month-by-month order count for the year.

Show the solution
SELECT MONTH(order_date) AS order_month, COUNT(*) AS orders
FROM Orders
GROUP BY MONTH(order_date)
ORDER BY order_month;

Grouping by a date part is the backbone of trend reporting. Remember its honest limitation: a month with zero orders produces no row, so a dashboard that must show empty months needs a calendar table to join against.

Scenario 6: Where are our customers?

Count customers per country, biggest first; break ties alphabetically.

Show the solution
SELECT country, COUNT(*) AS customers
FROM Customers
GROUP BY country
ORDER BY customers DESC, country;

Simple, but the tie-break matters: without the second ORDER BY key, equal counts come back in unpredictable order, and a report that shuffles between runs erodes trust in the numbers.

Scenario 7: Which department's people bring in the shipped revenue?

Attribute each Shipped order to the department of the employee who handled it, and total per department.

Show the solution
SELECT d.dept_name, SUM(o.order_total) AS shipped_revenue
FROM Orders o
JOIN Employees e ON e.emp_id = o.emp_id
JOIN Departments d ON d.dept_id = e.dept_id
WHERE o.status = 'Shipped'
GROUP BY d.dept_name
ORDER BY shipped_revenue DESC;

A two-hop join: Orders knows the employee, the employee knows the department. In this dataset the answer is a single row — only Sales handles orders — and saying “the data shows only one department closes orders” is exactly the kind of observation interviewers want to hear.

Scenario 8: What share of orders gets cancelled?

Management wants the cancellation rate as a percentage, one decimal place.

Show the solution
SELECT ROUND(SUM(CASE WHEN status = 'Cancelled' THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 1) AS cancelled_pct
FROM Orders;

The conditional-count trick: CASE turns each row into 1 or 0, SUM counts the ones, and dividing by COUNT(*) gives the share. The * 100.0 keeps the arithmetic in decimals — integer division would round the whole thing to zero in many databases.

Scenario 9: Which orders are above our average order value?

List order_id and order_total for every order larger than the overall average, biggest first.

Show the solution
SELECT order_id, order_total
FROM Orders
WHERE order_total > (SELECT AVG(order_total) FROM Orders)
ORDER BY order_total DESC;

A scalar subquery: the inner SELECT produces one number, and the outer WHERE compares every row against it. The follow-up interviewers like — “above their own customer’s average” — turns it into a correlated subquery, which is the harder cousin worth practising next.

Scenario 10: Who is our most valuable customer?

One row: the company with the highest lifetime spend across all their orders, and the amount.

Show the solution
SELECT c.company, SUM(o.order_total) AS lifetime_spend
FROM Customers c
JOIN Orders o ON o.customer_id = c.customer_id
GROUP BY c.company
ORDER BY lifetime_spend DESC
LIMIT 1;

Group, sort, take one. Worth saying in an interview: LIMIT 1 silently drops ties — if two customers tie for the top spot, only one appears. Handling ties properly is a RANK() job, which is where window functions enter.

Try it yourself

Every table these scenarios mention is already loaded in the playground. Write your attempt there before opening any solution - the struggle is the practice.

Open the Playground

How to practise these well

Resist reading solutions first — the reading feels like progress and teaches almost nothing. A better loop: attempt the scenario in the playground, compare against the solution, and note which decision you missed (the join direction, where the filter went, the tie-break). Then take the 42 checked exercises, which grade your answer automatically by running it.

Frequently asked questions

What kind of SQL questions do data analyst interviews ask?

Mostly business scenarios: given some tables, compute a metric, find the top performers, compare groups, spot the rows that are missing. Joins, GROUP BY, filtering aggregates, and the occasional subquery or window function cover the large majority.

How much SQL is enough for a data analyst interview?

Comfortable fluency with SELECT, WHERE, JOINs, GROUP BY and HAVING, plus subqueries and the ROW_NUMBER/RANK family of window functions. Depth beats breadth: writing a correct three-table join under time pressure impresses more than reciting exotic syntax.

Should I explain my thinking during an SQL interview?

Yes, out loud and continuously. Interviewers score how you notice ambiguity (which statuses count as revenue?), how you verify (checking row counts), and how you recover from a wrong first attempt - not just the final query.

Are these questions taken from real companies?

No. Every scenario is original, written specifically for this site’s own fictional sample database. Company interview questions are their property and often under NDA; these teach the same underlying patterns without copying anyone.