SQL Practice Problem

Number of orders per customer

Easy Aggregation

Schema and sample data

Customers
customer_idname
1Ava Torres
2Ben Ncube
3Cara Singh
4Deng Liu
5Emma Rossi
Orders
order_idcustomer_id
1011
1021
1031
1043
1053
1065
Show setup SQL (copy to run)
CREATE TABLE Customers (
    customer_id INT PRIMARY KEY,
    name        VARCHAR(50) NOT NULL
);

CREATE TABLE Orders (
    order_id    INT PRIMARY KEY,
    customer_id INT NOT NULL
);

INSERT INTO Customers (customer_id, name) VALUES
(1, 'Ava Torres'),
(2, 'Ben Ncube'),
(3, 'Cara Singh'),
(4, 'Deng Liu'),
(5, 'Emma Rossi');

INSERT INTO Orders (order_id, customer_id) VALUES
(101, 1),
(102, 1),
(103, 1),
(104, 3),
(105, 3),
(106, 5);
Your task

You have a Customers table and an Orders table. Return each customer name together with the number of orders they have placed, aliased as order_count. Include only customers who have at least one order, and sort the result by order_count from highest to lowest.

Expected result

Your query should return
nameorder_count
Ava Torres3
Cara Singh2
Emma Rossi1
Show hint

Join Customers to Orders on customer_id, then GROUP BY the customer so each group holds one customer and all of their order rows. COUNT(*) counts the rows in each group. An INNER JOIN naturally drops customers who never ordered, because they produce no matching rows.

Try to write the query yourself before you open this.

Show solution and explanation
SELECT c.name, COUNT(*) AS order_count
FROM Customers c
INNER JOIN Orders o ON o.customer_id = c.customer_id
GROUP BY c.name
ORDER BY order_count DESC;

The INNER JOIN matches each customer to their order rows on customer_id. Ava Torres has three matching rows, Cara Singh has two, and Emma Rossi has one, so after the join those customers appear that many times. Ben Ncube and Deng Liu have no orders, so the inner join produces no rows for them and they drop out of the result entirely.

GROUP BY c.name collapses the joined rows into one row per customer, and COUNT(*) counts the rows in each group, which is the number of orders. See the COUNT function reference for the difference between COUNT(*), COUNT(column), and COUNT(DISTINCT column). Finally ORDER BY order_count DESC sorts the busiest customers to the top.

One important variant: because this uses an INNER JOIN, customers with zero orders are silently excluded. If you need every customer listed, including those with a count of 0, switch to a LEFT JOIN and count the joined key rather than the rows: COUNT(o.order_id) instead of COUNT(*). COUNT(*) would wrongly return 1 for a customer with no orders because the outer join still yields one all-NULL row, whereas COUNT(order_id) ignores that NULL and returns 0. This same count-per-group pattern extends to the medium level.

Keep practising

Work through more Easy exercises, or test yourself with the SQL interview questions.