Brightlane's sales team wants to identify customers who have no orders on record.
Write a query to return the names of every customer who appears in the customer table but has no matching order.
Assumptions:
- The
customerstable contains every customer Brightlane has on file. - The
orderstable contains every order Brightlane has processed. - A customer with no orders has no row in
orderscarrying theiridascustomer_id.
Output:
- One row per customer with no orders, with a single column
customer_name.
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
c.name AS customer_name
FROM
customers c
FULL OUTER JOIN orders o ON c.id = o.customer_id
WHERE
o.id IS NULL The shape
WHERE o.id IS NULL after a FULL OUTER JOIN keeps only the customers whose id matched no row in orders. The orders side comes back fully NULL-padded on those rows, and the filter latches onto that pattern. Eight customers — Omar Jensen, Mark Hayes, Nina Irwin, and five more — have no order history on file.
Clause by clause
SELECT c.name AS customer_namereturns just the customer name. Everything else the join carries is scaffolding for the filter.FROM customers c FULL OUTER JOIN orders o ON c.id = o.customer_idruns the reconciliation. Customers who have placed orders pair up with each of their orders; customers with no orders are still kept, with the orders sideNULL-padded; any order whosecustomer_iddoesn't resolve is kept too, with the customers sideNULL-padded.WHERE o.id IS NULLruns after the join and keeps only the rows where the orders side came back empty. Matched rows have a realo.idand drop out. Orphan-order rows have a realo.idtoo (and aNULLcustomer name) and drop out. What's left is one row per customer with no orders — exactly the sales team's no-order list.
Why filter on o.id and not on o.customer_id
Reaching for WHERE o.customer_id IS NULL looks similar but tests the wrong column. An orphan order — an order row whose customer_id happened to be NULL in the source data — would slip through that filter even though it isn't a customer at all. Filtering on o.id is safer because id is the orders primary key; it's NULL only on rows the outer join padded in, never on real order rows. The general rule: the anti-join's IS NULL filter belongs on a column that can only be NULL because the join didn't match.
You practiced an anti-join from the customers side. The same answer comes out of a LEFT JOIN anchored on customers (taught in N018) or a FULL OUTER JOIN followed by an IS NULL filter on the orders side — different scaffolds, identical result.