Skip to course content
Free SQL course

SQL for Data Analysis and AI

Unit 09.02: CASE buckets and the missing ELSE

Unit ID: SQL-M09-U03 - Estimated active time: 13-16 minutes Objective: build category expressions that account for every row, including the ones you did not anticipate.

A CASE without ELSE returns NULL

SELECT COUNT(*)
FROM (SELECT CASE WHEN country = 'IN' THEN 'India' END AS bucket FROM customers)
WHERE bucket IS NULL;
-- 1999

1,999 customers fell through and became NULL: 1,699 with a non-India country and 300 with no country at all. If that expression fed a report, those 1,999 would appear as a blank category - or, after a WHERE bucket = … filter, vanish entirely.

Always close the expression

SELECT CASE
         WHEN country IS NULL THEN 'Unknown'
         WHEN country = 'IN'  THEN 'India'
         ELSE 'International'
       END        AS segment,
       COUNT(*)   AS customers
FROM customers
GROUP BY segment
ORDER BY customers DESC;
-- India         | 2813
-- International | 1699
-- Unknown       |  300

2,813 + 1,699 + 300 = 4,812. The buckets sum to the total, which is the property to check every time.

Order matters

CASE evaluates top to bottom and stops at the first match. Put the NULL test first: if country = 'IN' came first it would be UNKNOWN for NULL rows and fall through - correct here by luck, but fragile. Testing for the special case explicitly is what makes the logic robust rather than accidental.

The reconciliation check

SELECT SUM(customers) AS bucketed, (SELECT COUNT(*) FROM customers) AS total
FROM (
  SELECT CASE
           WHEN country IS NULL THEN 'Unknown'
           WHEN country = 'IN'  THEN 'India'
           ELSE 'International'
         END AS segment,
         COUNT(*) AS customers
  FROM customers GROUP BY segment
) t;
-- 4812 | 4812

If those two numbers differ, a row escaped your buckets. This is the same "do the parts sum to the whole" discipline as Module 3's three-way split and Module 4's grain check.

Practice

Build a three-band rating segmentation over feedback that accounts for all 500 rows, and prove it does.

Check your answer
SELECT CASE
         WHEN rating IS NULL THEN 'No rating'
         WHEN rating < 3     THEN 'Low'
         ELSE 'High'
       END      AS band,
       COUNT(*) AS responses
FROM feedback
GROUP BY band
ORDER BY responses DESC;
-- High      | 260
-- Low       | 180
-- No rating |  60

260 + 180 + 60 = 500. Without the NULL branch, the 60 unrated rows would have become NULL and been read as a data error rather than a real category.

Takeaway

Every CASE needs an ELSE, and every bucketing needs a check that the parts sum to the whole.

---