CASE in PostgreSQL explained with examples

CASE in PostgreSQL explained with examples

Databases are at the heart of most modern web applications, and PostgreSQL is one of the most popular relational database systems out there. One powerful feature of PostgreSQL—and SQL in general—is the CASE expression. It brings an element of conditional logic to the world of querying, allowing developers to define multiple outcomes based on specific conditions. This dynamic flexibility makes it an essential tool in the SQL toolkit.


The CASE expression in SQL provides a mechanism for introducing conditional logic directly within queries. By using CASE, one can craft queries that return different results based on specific conditions, making it invaluable for dynamic data retrieval and manipulation. In a world where data is king, being able to adapt and conditionally interact with that data is crucial.

Basic Structure of CASE

The CASE expression comes in two main flavors: Simple and Searched.

Simple CASE

The Simple CASE form is reminiscent of a switch-case construct in traditional programming languages. It evaluates a single expression and returns a value based on a specified condition. Its structure is generally as follows:

CASE expression
WHEN value1 THEN result1
WHEN value2 THEN result2
ELSE default_result

Searched CASE

Unlike the Simple CASE that evaluates a single expression against multiple values, the Searched CASE evaluates multiple conditions. Its structure is:

WHEN condition1 THEN result1
WHEN condition2 THEN result2
ELSE default_result

Simple CASE Example

Suppose you have a table students with a column grades. If you want to classify students based on their grades, a Simple CASE can be handy.

Query Demonstration

SELECT name, grade,
CASE grade
WHEN 'A' THEN 'Excellent'
WHEN 'B' THEN 'Good'
WHEN 'C' THEN 'Average'
ELSE 'Needs Improvement'
END as performance
FROM students;

The output might look like:

 name  | grade |     performance     
 Alice | A     | Excellent
 Bob   | C     | Average
 Eve   | B     | Good

Searched CASE Example

Using the same students table, let’s categorize students based on a range of grades.

Query Demonstration

SELECT name, score,
WHEN score >= 90 THEN 'Excellent'
WHEN score >= 70 AND score < 90 THEN 'Good'
WHEN score >= 50 AND score < 70 THEN 'Average'
ELSE 'Needs Improvement'
END as performance
FROM students;

Using CASE in Different Parts of a Query

The versatility of the CASE expression shines when it’s used in various segments of an SQL query.

In the SELECT Clause

You’ve already seen this in action in the previous examples, where we classified student performance based on grades or scores.

In the WHERE Clause

You can use CASE to create dynamic filters.

SELECT name, score
FROM students
WHEN score >= 90 THEN true
ELSE false

In the ORDER BY Clause

To conditionally order data:

SELECT name, score
FROM students
WHEN score >= 90 THEN 1

In the GROUP BY Clause

Group data conditionally:

WHEN score >= 90 THEN 'High Scorers'
ELSE 'Others'
END as category, COUNT(*)
FROM students
GROUP BY category;

With Aggregate Functions

Incorporate CASE with aggregate functions to gain more insights:

WHEN score >= 90 THEN 'High Scorers'
ELSE 'Others'
END as category, COUNT(*), SUM(score)
FROM students
GROUP BY category;

Combining CASE with Other SQL Functions

One of the intriguing aspects of SQL is its ability to combine various functions for more intricate operations. In PostgreSQL, the CASE expression isn’t an exception. Let’s see how we can enhance its capability by coupling it with other functions.

String Functions

Imagine you want to classify user names based on their initials. You might use CASE along with the SUBSTRING function:

SELECT username,
WHEN SUBSTRING(username, 1, 1) BETWEEN 'A' AND 'M' THEN 'Group A-M'
ELSE 'Group N-Z'
END AS user_group
FROM users;

Furthermore, you can even combine results using the CONCAT function:

SELECT username,
CONCAT('Belongs to: ',
WHEN SUBSTRING(username, 1, 1) BETWEEN 'A' AND 'M' THEN 'Group A-M'
ELSE 'Group N-Z'
END) AS user_classification
FROM users;

Date Functions

You can also harness the power of CASE with date functions. For instance, to categorize users by their age:

SELECT username, birthdate,
WHEN AGE(birthdate) < interval '20 years' THEN 'Teen'
WHEN AGE(birthdate) BETWEEN interval '20 years' AND interval '40 years' THEN 'Adult'
ELSE 'Senior'
END AS age_group
FROM users;

Or to break down sales by quarters using the DATE_PART function:

SELECT sale_date,
WHEN DATE_PART('quarter', sale_date) = 1 THEN 'Q1'
WHEN DATE_PART('quarter', sale_date) = 2 THEN 'Q2'
WHEN DATE_PART('quarter', sale_date) = 3 THEN 'Q3'
END AS quarter
FROM sales;

Mathematical Functions

The flexibility of CASE isn’t just limited to strings or dates. Consider a scenario where you wish to give a discount based on the purchase amount:

SELECT purchase_amount,
purchase_amount -
WHEN purchase_amount > 1000 THEN purchase_amount * 0.1
END AS discounted_amount
FROM orders;

This query gives a 10% discount for orders above $1000.

Nested CASE Expressions

There might be situations when a simple CASE expression won’t suffice. Here, nested CASE expressions come into play, allowing you to evaluate conditions within conditions.

Query Demonstration

To illustrate, let’s categorize products by their price and stock levels:

1SELECT product_name, price, stock,
3 WHEN price > 100 THEN
5 WHEN stock < 10 THEN 'Expensive, Low Stock'
6 ELSE 'Expensive, Adequate Stock'
10 WHEN stock < 10 THEN 'Affordable, Low Stock'
11 ELSE 'Affordable, Adequate Stock'
12 END
13 END AS product_status
14FROM products;

CASE with JOIN Operations

The power of CASE isn’t confined to single tables. You can use it within JOIN operations to generate more meaningful insights.

Query Examples and Results

Consider two tables: orders and products. To list products and classify orders based on their total sale:

SELECT p.product_name,
WHEN SUM(o.order_amount) > 10000 THEN 'High Selling'
ELSE 'Low Selling'
END AS sales_status
FROM orders o
JOIN products p ON o.product_id = p.id
GROUP BY p.product_name;

Common Pitfalls and Best Practices

While CASE is potent, it’s not without challenges. Here are some pitfalls to watch out for and best practices to adopt:

Null Values

Remember that NULL values can be tricky with CASE. Always handle them explicitly to avoid unexpected results:

WHEN column IS NULL THEN 'Unknown'
ELSE column

Data Type Consistency

Ensure that all branches of your CASE expression return values of the same or compatible data types. Otherwise, PostgreSQL might throw an error.

Performance Considerations

Overuse of CASE, especially in nested scenarios or large datasets, can impact query performance. It’s a good practice to monitor query execution times and optimize as necessary.

Advanced Use Cases

Dynamic Pivot Tables

Pivot tables, though not natively supported in PostgreSQL, can be mimicked using CASE. For instance, to pivot sales data by months:

SELECT product,
SUM(CASE WHEN DATE_PART('month', sale_date) = 1 THEN sale_amount ELSE 0 END) AS Jan,
SUM(CASE WHEN DATE_PART('month', sale_date) = 2 THEN sale_amount ELSE 0 END) AS Feb,
FROM sales
GROUP BY product;

Conditional Aggregation

Aggregate functions can be paired with CASE for conditional logic:

SELECT product,
SUM(CASE WHEN region = 'North' THEN sale_amount ELSE 0 END) AS North_Sales,
SUM(CASE WHEN region = 'South' THEN sale_amount ELSE 0 END) AS South_Sales
FROM sales
GROUP BY product;

Creating Dynamic Columns

With CASE, you can conditionally produce columns based on data values. For instance:

SELECT username,
CASE WHEN login_count > 10 THEN 'Active User' ELSE NULL END AS Active,
CASE WHEN login_count <= 10 THEN 'Inactive User' ELSE NULL END AS Inactive
FROM users;

Alternatives to CASE


COALESCE is a handy function in PostgreSQL that returns the first non-NULL value in the list:

SELECT COALESCE(column1, column2, 'default_value') FROM table_name;

It’s particularly useful as an alternative to CASE when checking for NULL values.

NULLIF Function

NULLIF returns NULL if its two arguments are equal, otherwise, it returns the first argument:

SELECT NULLIF(column, 'value_to_compare') FROM table_name;

It can serve as a simpler alternative to CASE in some scenarios.


The CASE expression is an indispensable tool in the PostgreSQL arsenal, offering conditional logic right within SQL. Its adaptability with other functions, and its applications from basic to advanced scenarios, highlights its significance. Embrace it, but remember to be mindful of the best practices to harness its full potential.

Sharing is caring

Did you like what Mehul Mohan wrote? Thank them for their work by sharing it on social media.


No comments so far