✏️ Explanatory Question

Predict the output — why does COUNT(*) show 1 for customers with zero orders in a LEFT JOIN?

👁 11 Views
📘 Detailed Answer
🟢 Easy
💡

Answer with Explanation

85

Why does COUNT(*) show 1 for customers with zero orders in a LEFT JOIN?

Level: Hard — A subtle counting bug that silently inflates "zero-activity" numbers in reports.

Scenario: You build a "orders per customer" report using LEFT JOIN so that customers with no orders still appear. But the report shows customers with 0 orders as having 1 order. Finance is confused why "inactive" customers show activity. Where's the bug?

Sample Data

customers

customer_idname
1Rumman
2Krushna
3Swetha

orders

order_idcustomer_id
1011
1021
1032

Note: Swetha (id 3) has no orders at all.

The cause: COUNT(*) counts rows, not orders. In a LEFT JOIN, Swetha still produces one row (with all order columns as NULL). So COUNT(*) counts that one "phantom" row as 1. The fix is COUNT(o.order_id), which counts only non-NULL order values — giving 0 for Swetha.

Why interviewers ask this: It tests the crucial difference between COUNT(*) (counts rows, including the NULL-filled placeholder row) and COUNT(column) (ignores NULLs) — a distinction that produces silently wrong reports.

Predict the Output

SELECT c.name, COUNT(*) AS order_count
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_id, c.name;

COUNT(*) — WRONG

nameorder_count
Rumman2
Krushna1
Swetha1 ← wrong!

COUNT(o.order_id) — RIGHT

nameorder_count
Rumman2
Krushna1
Swetha0 ✓

The Bug and the Fix

-- THE BUG: COUNT(*) counts the NULL-filled placeholder row as 1
SELECT c.name, COUNT(*) AS order_count
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_id, c.name;
-- Swetha shows 1 (the phantom row)

-- THE FIX: COUNT a column from the RIGHT table (NULLs are ignored)
SELECT c.name, COUNT(o.order_id) AS order_count
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_id, c.name;
-- Swetha correctly shows 0

-- Same idea for SUM: wrap with COALESCE to avoid NULL totals
SELECT c.name, COALESCE(SUM(o.amount), 0) AS total_spent
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_id, c.name;
The rule: In a LEFT JOIN, always COUNT() a non-nullable column from the right-hand (joined) table — typically its primary key. Never use COUNT(*) when you want to count matched rows only.
Interviewer follow-up: "What if you also want the count of DISTINCT products per customer?" → Use COUNT(DISTINCT o.product_id), which both ignores NULLs and removes duplicate products — combining two NULL-safe behaviours in one.