Customers Without Orders
List customers who have never placed an order using an anti-join.
Start practiceProblem statement
Prompt
Given the customers and orders tables below, write a query that returns the name of every customer who has never placed an order.
- Each customer should appear at most once in the result.
- Only the customer
nameshould be returned — no other columns. orders.customer_idmay beNULL; such orders do not belong to any customer and must not rescue anyone.
Example
| customers | orders | ||
|---|---|---|---|
| id | name | id | customer_id |
| 1 | Alice | 1 | 1 |
| 2 | Bob | 2 | 3 |
| 3 | Carol | 3 | NULL |
| 4 | Dave |
Expected result:
| name |
|---|
| Bob |
| Dave |
Constraints
customers.idis the primary key.orders.customer_idreferencescustomers.idbut is nullable.
Tips
- This is an anti-join: keep rows from the left side that have no match on the right.
LEFT JOIN+WHERE orders.id IS NULLandNOT EXISTSare the two idiomatic forms.- If you use a subquery with
NOT IN, remember howNULLvalues behave insideNOT IN (…).
Schema
CREATE TABLE customers (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL
);
CREATE TABLE orders (
id INTEGER PRIMARY KEY,
customer_id INTEGER REFERENCES customers(id) -- NULL allowed
);
Sample data
INSERT INTO customers (id, name) VALUES
(1, 'Alice'),
(2, 'Bob'),
(3, 'Carol'),
(4, 'Dave');
INSERT INTO orders (id, customer_id) VALUES
(1, 1),
(2, 1),
(3, 3),
(4, 3);
Additional hidden fixtures are applied during validation to test edge cases.
Solution
One correct approach — try solving it yourself in the practice editor first, then compare. There is usually more than one valid solution.
-- Reference: one row per customer with no matching order.
SELECT c.name
FROM customers c
WHERE NOT EXISTS (
SELECT 1 FROM orders o WHERE o.customer_id = c.id
)
ORDER BY c.id;
Key concepts
- LEFT JOIN
- NOT EXISTS
- Anti-join
- NULL filtering
Related questions
- easyEmployee BonusReport every employee's name and bonus, including those with none.
- easyEmployees Earning More Than Their ManagerFind employees whose salary is greater than their direct manager's salary.
- mediumNth Highest SalaryReturn the third-highest distinct salary, or NULL when it does not exist.
- easySecond Highest SalaryReturn the second-highest distinct salary, or NULL when it does not exist.
- easyVisits Without TransactionsCount visits with no transactions per customer.