Skip to content

CASE WHEN

CASE WHEN expressions provide conditional logic in SQL queries, similar to if-else statements in programming languages.

Syntax

Simple CASE

Compare a value against multiple options:

sql
CASE expression
    WHEN value1 THEN result1
    WHEN value2 THEN result2
    ...
    [ELSE default_result]
END

Searched CASE

Evaluate multiple conditions:

sql
CASE
    WHEN condition1 THEN result1
    WHEN condition2 THEN result2
    ...
    [ELSE default_result]
END

Simple CASE

Compare an expression against specific values.

Basic Example

sql
SELECT
    name,
    status,
    CASE status
        WHEN 'active' THEN 'A'
        WHEN 'inactive' THEN 'I'
        WHEN 'pending' THEN 'P'
        ELSE 'U'
    END AS status_code
FROM users.csv

With Column Alias

sql
SELECT
    product,
    CASE category
        WHEN 'electronics' THEN 'Tech'
        WHEN 'clothing' THEN 'Apparel'
        WHEN 'food' THEN 'Grocery'
        ELSE 'Other'
    END AS category_name
FROM products.csv

Multiple Values Same Result

sql
SELECT
    day,
    CASE day
        WHEN 'Saturday' THEN 'Weekend'
        WHEN 'Sunday' THEN 'Weekend'
        ELSE 'Weekday'
    END AS day_type
FROM schedule.csv

Searched CASE

Evaluate conditions (more flexible than simple CASE).

Basic Example

sql
SELECT
    name,
    score,
    CASE
        WHEN score >= 90 THEN 'A'
        WHEN score >= 80 THEN 'B'
        WHEN score >= 70 THEN 'C'
        WHEN score >= 60 THEN 'D'
        ELSE 'F'
    END AS grade
FROM students.csv

Multiple Conditions

sql
SELECT
    name,
    age,
    income,
    CASE
        WHEN age < 18 THEN 'Minor'
        WHEN age >= 65 THEN 'Senior'
        WHEN income > 100000 THEN 'High Income'
        ELSE 'Standard'
    END AS category
FROM customers.csv

Range Conditions

sql
SELECT
    product,
    price,
    CASE
        WHEN price < 10 THEN 'Budget'
        WHEN price BETWEEN 10 AND 50 THEN 'Mid-range'
        WHEN price BETWEEN 51 AND 100 THEN 'Premium'
        ELSE 'Luxury'
    END AS tier
FROM products.csv

CASE in Different Clauses

In SELECT

sql
SELECT
    name,
    CASE WHEN age >= 18 THEN 'Adult' ELSE 'Minor' END AS age_group
FROM users.csv

In WHERE

sql
SELECT * FROM orders.csv
WHERE CASE
    WHEN priority = 'high' THEN total > 100
    WHEN priority = 'low' THEN total > 500
    ELSE total > 250
END

In ORDER BY

sql
SELECT * FROM tasks.csv
ORDER BY CASE priority
    WHEN 'critical' THEN 1
    WHEN 'high' THEN 2
    WHEN 'medium' THEN 3
    WHEN 'low' THEN 4
    ELSE 5
END

In GROUP BY

sql
SELECT
    CASE
        WHEN age < 18 THEN 'Under 18'
        WHEN age BETWEEN 18 AND 35 THEN '18-35'
        WHEN age BETWEEN 36 AND 55 THEN '36-55'
        ELSE 'Over 55'
    END AS age_group,
    COUNT(*) AS count
FROM users.csv
GROUP BY CASE
    WHEN age < 18 THEN 'Under 18'
    WHEN age BETWEEN 18 AND 35 THEN '18-35'
    WHEN age BETWEEN 36 AND 55 THEN '36-55'
    ELSE 'Over 55'
END

CASE with Aggregation

Conditional Counting

sql
SELECT
    department,
    COUNT(*) AS total,
    SUM(CASE WHEN status = 'active' THEN 1 ELSE 0 END) AS active,
    SUM(CASE WHEN status = 'inactive' THEN 1 ELSE 0 END) AS inactive
FROM employees.csv
GROUP BY department

Conditional Sum

sql
SELECT
    category,
    SUM(CASE WHEN month = 'Jan' THEN sales ELSE 0 END) AS jan_sales,
    SUM(CASE WHEN month = 'Feb' THEN sales ELSE 0 END) AS feb_sales,
    SUM(CASE WHEN month = 'Mar' THEN sales ELSE 0 END) AS mar_sales
FROM monthly_sales.csv
GROUP BY category

Percentage Calculation

sql
SELECT
    department,
    ROUND(
        100.0 * SUM(CASE WHEN gender = 'F' THEN 1 ELSE 0 END) / COUNT(*),
        1
    ) AS female_pct
FROM employees.csv
GROUP BY department

Nested CASE

CASE expressions can be nested:

sql
SELECT
    name,
    CASE region
        WHEN 'North' THEN
            CASE WHEN sales > 1000 THEN 'North Star' ELSE 'North' END
        WHEN 'South' THEN
            CASE WHEN sales > 1000 THEN 'South Star' ELSE 'South' END
        ELSE 'Other'
    END AS category
FROM sales_reps.csv

CASE with NULL

Handle NULL values:

sql
SELECT
    name,
    CASE
        WHEN email IS NULL THEN 'No Email'
        WHEN email LIKE '%@company.com' THEN 'Internal'
        ELSE 'External'
    END AS email_type
FROM contacts.csv

COALESCE Alternative

For simple NULL replacement, use COALESCE:

sql
-- Using CASE
SELECT CASE WHEN name IS NULL THEN 'Unknown' ELSE name END FROM users.csv

-- Using COALESCE (simpler)
SELECT COALESCE(name, 'Unknown') FROM users.csv

Common Patterns

Status Mapping

sql
SELECT
    order_id,
    CASE status
        WHEN 1 THEN 'Pending'
        WHEN 2 THEN 'Processing'
        WHEN 3 THEN 'Shipped'
        WHEN 4 THEN 'Delivered'
        WHEN 5 THEN 'Cancelled'
        ELSE 'Unknown'
    END AS status_name
FROM orders.csv

Grade Calculation

sql
SELECT
    student,
    score,
    CASE
        WHEN score >= 90 THEN 'A'
        WHEN score >= 80 THEN 'B'
        WHEN score >= 70 THEN 'C'
        WHEN score >= 60 THEN 'D'
        ELSE 'F'
    END AS grade,
    CASE
        WHEN score >= 60 THEN 'Pass'
        ELSE 'Fail'
    END AS result
FROM exams.csv

Date Categorization

sql
SELECT
    order_id,
    order_date,
    CASE
        WHEN EXTRACT('dow', order_date) IN (0, 6) THEN 'Weekend'
        ELSE 'Weekday'
    END AS day_type,
    CASE EXTRACT('month', order_date)
        WHEN 1 THEN 'Q1'
        WHEN 2 THEN 'Q1'
        WHEN 3 THEN 'Q1'
        WHEN 4 THEN 'Q2'
        WHEN 5 THEN 'Q2'
        WHEN 6 THEN 'Q2'
        WHEN 7 THEN 'Q3'
        WHEN 8 THEN 'Q3'
        WHEN 9 THEN 'Q3'
        ELSE 'Q4'
    END AS quarter
FROM orders.csv

Pivot Table

Transform rows to columns:

sql
SELECT
    product,
    MAX(CASE WHEN region = 'North' THEN sales END) AS north,
    MAX(CASE WHEN region = 'South' THEN sales END) AS south,
    MAX(CASE WHEN region = 'East' THEN sales END) AS east,
    MAX(CASE WHEN region = 'West' THEN sales END) AS west
FROM regional_sales.csv
GROUP BY product

Risk Scoring

sql
SELECT
    customer_id,
    CASE
        WHEN late_payments > 3 AND credit_score < 600 THEN 'High Risk'
        WHEN late_payments > 1 OR credit_score < 650 THEN 'Medium Risk'
        ELSE 'Low Risk'
    END AS risk_level
FROM customers.csv

Best Practices

1. Always Include ELSE

Prevent unexpected NULLs:

sql
-- Good: explicit default
CASE status WHEN 'A' THEN 'Active' ELSE 'Unknown' END

-- Risky: may return NULL
CASE status WHEN 'A' THEN 'Active' END

2. Order Conditions Carefully

First matching condition wins:

sql
-- Correct order (most specific first)
CASE
    WHEN score = 100 THEN 'Perfect'
    WHEN score >= 90 THEN 'A'
    WHEN score >= 80 THEN 'B'
    ELSE 'C or below'
END

-- Wrong order (90-99 never matched)
CASE
    WHEN score >= 80 THEN 'B'  -- Matches 90-99 too!
    WHEN score >= 90 THEN 'A'  -- Never reached
    ELSE 'Other'
END

3. Use Simple CASE When Possible

sql
-- Simple CASE (cleaner)
CASE status WHEN 'A' THEN 'Active' WHEN 'I' THEN 'Inactive' END

-- Searched CASE (more verbose)
CASE WHEN status = 'A' THEN 'Active' WHEN status = 'I' THEN 'Inactive' END

4. Extract Complex Logic

For readability, consider breaking complex CASE into multiple columns:

sql
SELECT
    name,
    CASE WHEN age >= 18 THEN 'Adult' ELSE 'Minor' END AS age_category,
    CASE WHEN income > 50000 THEN 'Above Avg' ELSE 'Below Avg' END AS income_category
FROM users.csv

All rights reserved.