The CASE
statement in SQL Server is a powerful control-flow construct that allows you to add conditional logic to your SQL queries. Think of it as SQL’s equivalent to an if-else
statement in programming languages. It enables you to evaluate different conditions and return different values based on those conditions, all within a single query. This makes your SQL code more flexible and capable of handling complex data transformations and reporting requirements.
This comprehensive guide will delve deep into the intricacies of the SQL Server CASE WHEN
statement, exploring its syntax, different formats, and practical applications with examples. Whether you are a database administrator, a data analyst, or a developer working with SQL Server, understanding and utilizing CASE WHEN
effectively will significantly enhance your SQL skillset.
Understanding the Two Flavors of SQL Server CASE WHEN
SQL Server CASE
expressions come in two primary formats, each suited for different scenarios:
-
Simple CASE Expression: This format compares a single input expression against a series of simple expressions. It checks for equality and returns a result when a match is found.
-
Searched CASE Expression: This more versatile format evaluates a series of Boolean expressions. It returns a result when the first Boolean expression evaluates to TRUE.
Both formats offer an optional ELSE
clause to define a default return value if none of the conditions are met. Let’s break down each format in detail.
Syntax of SQL Server CASE WHEN
It’s crucial to grasp the syntax to effectively use CASE WHEN
. Here’s a breakdown of the syntax for both simple and searched CASE
expressions in SQL Server:
Simple CASE Expression Syntax:
CASE input_expression
WHEN when_expression THEN result_expression
[ ...n ]
[ ELSE else_result_expression ]
END
Searched CASE Expression Syntax:
CASE
WHEN Boolean_expression THEN result_expression
[ ...n ]
[ ELSE else_result_expression ]
END
Let’s dissect the components:
CASE
: Initiates theCASE
expression.input_expression
(Simple CASE only): The expression you want to evaluate.WHEN when_expression
: Specifies the value to compare againstinput_expression
(in Simple CASE) or a Boolean condition to evaluate (in Searched CASE).THEN result_expression
: Defines the value to return if the precedingWHEN
condition is met.ELSE else_result_expression
(Optional): Specifies the value to return if none of theWHEN
conditions are met. If omitted and no condition is TRUE,CASE
returnsNULL
.END
: Terminates theCASE
expression.
Understanding these syntax variations is key to choosing the right CASE
format for your specific needs.
Diving Deeper: Simple CASE Expression
The simple CASE
expression excels when you need to compare a single value against several possible values for equality. It streamlines your code when you’re essentially performing a series of “is equal to” checks.
How it Works:
The simple CASE
expression takes an input_expression
and compares it sequentially to each when_expression
in the WHEN
clauses.
- It evaluates
input_expression = when_expression
for eachWHEN
clause in the order specified. - If a match is found (the expressions are equal), it immediately returns the corresponding
result_expression
from theTHEN
clause and stops evaluating further conditions. - If no
WHEN
clause matches theinput_expression
, and anELSE
clause is present, it returns theelse_result_expression
. If noELSE
clause is provided and no match is found, it returnsNULL
.
Example: Categorizing Product Lines
Let’s imagine you have a Product
table with a ProductLine
column containing codes like ‘R’, ‘M’, ‘T’, and ‘S’. You want to display more descriptive categories in your query results. The simple CASE
expression is perfect for this:
USE AdventureWorks2022;
GO
SELECT
ProductNumber,
Category = CASE ProductLine
WHEN 'R' THEN 'Road'
WHEN 'M' THEN 'Mountain'
WHEN 'T' THEN 'Touring'
WHEN 'S' THEN 'Other sale items'
ELSE 'Not for sale'
END,
Name
FROM Production.Product
ORDER BY ProductNumber;
GO
Alt Text: SQL query using simple CASE expression to categorize product lines in AdventureWorks2022 database, showing ProductNumber, Category derived from ProductLine, and Name, ordered by ProductNumber.
In this example, ProductLine
is the input_expression
. The CASE
statement checks if ProductLine
is equal to ‘R’, ‘M’, ‘T’, or ‘S’, and returns the corresponding category name. If ProductLine
doesn’t match any of these, the ELSE
clause assigns ‘Not for sale’ as the category.
Unleashing Flexibility: Searched CASE Expression
The searched CASE
expression provides significantly more flexibility than its simple counterpart. It allows you to evaluate a wide range of conditions, not just equality, making it suitable for complex conditional logic.
How it Works:
The searched CASE
expression evaluates Boolean expressions defined in each WHEN
clause.
- It evaluates each
Boolean_expression
sequentially, in the order specified. - The first
Boolean_expression
that evaluates toTRUE
triggers the return of its associatedresult_expression
from theTHEN
clause. Evaluation stops at this point. - If none of the
Boolean_expression
s areTRUE
, and anELSE
clause exists, theelse_result_expression
is returned. Otherwise, if noELSE
clause is present,NULL
is returned.
Example: Defining Price Ranges
Consider a scenario where you need to categorize products based on their ListPrice
into different price ranges. The searched CASE
expression shines here because you need to evaluate ranges, not just specific values:
USE AdventureWorks2022;
GO
SELECT
ProductNumber,
Name,
"Price Range" = CASE
WHEN ListPrice = 0 THEN 'Mfg item - not for resale'
WHEN ListPrice BETWEEN 1 AND 50 THEN 'Low'
WHEN ListPrice BETWEEN 51 AND 250 THEN 'Medium'
WHEN ListPrice > 250 THEN 'High'
ELSE 'Unknown'
END
FROM Production.Product
ORDER BY ProductNumber;
GO
Alt Text: SQL query using searched CASE expression to define price ranges for products in AdventureWorks2022 database based on ListPrice, showing ProductNumber, Name, and “Price Range” category, ordered by ProductNumber.
Here, we use Boolean expressions with operators like =
, BETWEEN
, and >
in the WHEN
clauses to define price ranges. The CASE
statement checks these conditions and assigns a “Price Range” label accordingly. The ELSE 'Unknown'
handles cases where ListPrice
might fall outside the defined ranges (though in this specific example, it’s unlikely to be hit given the conditions).
Practical Applications: CASE WHEN in Different SQL Statements
The versatility of CASE WHEN
extends to various SQL statements and clauses. Let’s explore its usage in common scenarios:
1. CASE WHEN in SELECT Statements
As demonstrated in the previous examples, CASE WHEN
is frequently used within SELECT
statements to create calculated columns, categorize data, or transform values for reporting purposes. It allows you to dynamically generate different output based on data conditions, directly within your queries.
2. CASE WHEN in ORDER BY Clauses
You can leverage CASE WHEN
to control the sorting order of your query results dynamically. This is especially useful when you need to sort based on different criteria depending on the data itself.
Example: Conditional Sorting by Employee Type
Let’s say you want to sort employees differently based on whether they are salaried or not. Salaried employees should be sorted by BusinessEntityID
in descending order, while non-salaried employees should be sorted by BusinessEntityID
in ascending order.
SELECT
BusinessEntityID,
SalariedFlag
FROM HumanResources.Employee
ORDER BY
CASE
WHEN SalariedFlag = 1 THEN BusinessEntityID
END DESC, -- Sort salaried (1) descending
CASE
WHEN SalariedFlag = 0 THEN BusinessEntityID
END ASC; -- Sort non-salaried (0) ascending
GO
Alt Text: SQL query using CASE WHEN in ORDER BY clause to conditionally sort employees in HumanResources.Employee table based on SalariedFlag, showing BusinessEntityID and SalariedFlag, with salaried employees sorted descending and non-salaried ascending.
This query uses two CASE
expressions within the ORDER BY
clause. The first CASE
applies only to salaried employees (SalariedFlag = 1
) and sorts them in descending order. The second CASE
applies to non-salaried employees (SalariedFlag = 0
) and sorts them in ascending order. Employees are first sorted by the first CASE
and then within those groups by the second CASE
.
3. CASE WHEN in UPDATE Statements
CASE WHEN
empowers you to conditionally update data in your tables. You can set different values for a column based on the existing values in the row or related data.
Example: Adjusting Vacation Hours Conditionally
Imagine a scenario where you need to adjust employee vacation hours. If subtracting 10 hours would result in negative vacation hours, you want to add 40 hours instead. Otherwise, simply add 20 hours.
USE AdventureWorks2022;
GO
UPDATE HumanResources.Employee
SET VacationHours = (
CASE
WHEN ((VacationHours - 10.00) < 0) THEN VacationHours + 40.00
ELSE VacationHours + 20.00
END
)
WHERE SalariedFlag = 0; -- Apply only to non-salaried employees
GO
Alt Text: SQL query using CASE WHEN in UPDATE statement to conditionally adjust VacationHours for non-salaried employees in HumanResources.Employee table, adding 40 hours if subtracting 10 results in negative hours, otherwise adding 20 hours.
This UPDATE
statement uses a CASE
expression to determine how to update VacationHours
based on a condition. It checks if subtracting 10 hours would lead to a negative value and applies different logic accordingly.
4. CASE WHEN in SET Statements (Within Functions)
Within user-defined functions, CASE WHEN
can be used in SET
statements to assign values to variables based on conditions. This allows you to build logic into your functions to determine return values or internal calculations.
Example: Determining Contact Type in a Function
Consider a function that retrieves contact information for a given BusinessEntityID
. The contact type might be ‘Employee’, ‘Vendor’, ‘Store Contact’, or ‘Consumer’ depending on the presence of the BusinessEntityID
in different tables.
USE AdventureWorks2022;
GO
CREATE FUNCTION dbo.GetContactInformation (@BusinessEntityID INT)
RETURNS @retContactInformation TABLE (
BusinessEntityID INT NOT NULL,
FirstName NVARCHAR(50) NULL,
LastName NVARCHAR(50) NULL,
ContactType NVARCHAR(50) NULL,
PRIMARY KEY CLUSTERED (BusinessEntityID ASC)
)
AS
BEGIN
DECLARE @FirstName NVARCHAR(50), @LastName NVARCHAR(50), @ContactType NVARCHAR(50);
-- Get common contact information
SELECT
@BusinessEntityID = BusinessEntityID,
@FirstName = FirstName,
@LastName = LastName
FROM Person.Person
WHERE BusinessEntityID = @BusinessEntityID;
SET @ContactType = CASE
-- Check for employee
WHEN EXISTS (SELECT * FROM HumanResources.Employee AS e WHERE e.BusinessEntityID = @BusinessEntityID) THEN 'Employee'
-- Check for vendor
WHEN EXISTS (SELECT * FROM Person.BusinessEntityContact AS bec WHERE bec.BusinessEntityID = @BusinessEntityID) THEN 'Vendor'
-- Check for store contact
WHEN EXISTS (SELECT * FROM Purchasing.Vendor AS v WHERE v.BusinessEntityID = @BusinessEntityID) THEN 'Store Contact'
-- Check for individual consumer
WHEN EXISTS (SELECT * FROM Sales.Customer AS c WHERE c.PersonID = @BusinessEntityID) THEN 'Consumer'
ELSE 'Unknown' -- Default if no type is found
END;
-- Return the information to the caller
IF @BusinessEntityID IS NOT NULL
BEGIN
INSERT INTO @retContactInformation
SELECT @BusinessEntityID, @FirstName, @LastName, @ContactType;
END;
RETURN;
END;
GO
SELECT * FROM dbo.GetContactInformation(2200); -- Example: Employee
GO
SELECT * FROM dbo.GetContactInformation(5); -- Example: Vendor
GO
Alt Text: SQL code for a user-defined function dbo.GetContactInformation in AdventureWorks2022 database, using CASE WHEN in a SET statement to determine ContactType based on existence of BusinessEntityID in Employee, Vendor, BusinessEntityContact, or Customer tables.
In this function, the CASE
expression within the SET @ContactType
statement checks for the existence of the @BusinessEntityID
in different tables to determine the appropriate ContactType
value.
5. CASE WHEN in HAVING Clauses
You can use CASE WHEN
within HAVING
clauses to filter grouped data based on conditional aggregate calculations. This allows you to apply different filtering criteria to different groups based on aggregate values.
Example: Filtering Job Titles by Maximum Rate and Employee Type
Suppose you want to retrieve job titles and their maximum pay rates, but you want to filter these titles differently based on whether the employees in that job title are salaried or not. For salaried employees, you might want to filter for job titles with a maximum rate greater than $40, while for non-salaried employees, the threshold might be $15.
USE AdventureWorks2022;
GO
SELECT
JobTitle,
MAX(ph1.Rate) AS MaximumRate
FROM HumanResources.Employee AS e
INNER JOIN HumanResources.EmployeePayHistory AS ph1
ON e.BusinessEntityID = ph1.BusinessEntityID
GROUP BY JobTitle
HAVING (
MAX(CASE WHEN SalariedFlag = 1 THEN ph1.Rate ELSE NULL END) > 40.00 -- Salaried employees, max rate > 40
OR
MAX(CASE WHEN SalariedFlag = 0 THEN ph1.Rate ELSE NULL END) > 15.00 -- Non-salaried employees, max rate > 15
)
ORDER BY MaximumRate DESC;
GO
Alt Text: SQL query using CASE WHEN in HAVING clause to filter job titles in HumanResources.Employee table based on maximum pay rate (MaximumRate) and SalariedFlag, showing JobTitle and MaximumRate, filtered conditionally for salaried and non-salaried employees.
This query uses CASE WHEN
within the HAVING
clause to calculate conditional maximum rates for salaried and non-salaried employees separately within each job title group. It then filters based on these conditional maximum rates, applying different thresholds for salaried and non-salaried groups.
Important Considerations When Using SQL Server CASE WHEN
While CASE WHEN
is powerful, keep these points in mind:
- Nesting Limits: SQL Server allows up to 10 levels of nesting in
CASE
expressions. While this is usually sufficient, deeply nestedCASE
statements can become complex and harder to read. Consider simplifying logic or breaking it down if you approach this limit. - Evaluation Order:
CASE
expressions evaluate conditions sequentially and stop at the firstTRUE
condition. This short-circuiting behavior is important to understand, especially when conditions might overlap. The order ofWHEN
clauses matters. - NULL Handling: If no
WHEN
condition is met and noELSE
clause is specified,CASE
returnsNULL
. Be mindful of this, especially in calculations or comparisons. Also, ensure at least oneTHEN
orELSE
expression is not explicitlyNULL
to avoid error 8133 if all result expressions could potentially return NULL. - Data Type Precedence: The return type of a
CASE
expression is determined by the data type precedence of theresult_expression
s and the optionalelse_result_expression
. Ensure data types are compatible or consider explicit casting if necessary.
Conclusion
SQL Server CASE WHEN
is an indispensable tool for adding conditional logic to your SQL queries. Mastering both the simple and searched CASE
expressions, and understanding their applications across different SQL statements, will significantly enhance your ability to write flexible, powerful, and data-driven SQL code. By using CASE WHEN
effectively, you can transform, categorize, and manipulate your data directly within your queries, making your SQL solutions more robust and adaptable to diverse requirements.