In this article, we will see how CASE can be used in any statement or clause that allows a valid expression.
Background
Here, we are going to check examples of how CASE
can be used in any statement or clause that allows a valid expression. For example, we usually use CASE
in statements such as SELECT
, UPDATE
, DELETE
and SET
. CASE
can also be used with JOIN
, WHERE
, ORDER BY
and HAVING
clauses. Let us check some examples.
CASE Types
There are two types of CASE
:
- Simple CASE: Allows only an equality check
- Searched CASE: Allows multiple checks
Simple CASE
CASE Expression
WHEN Value1 THEN Result1
WHEN Value2 THEN Result2
…
ELSE Result
END
DECLARE @userTypeId INT = 2;
DECLARE @userType VARCHAR(100);
SET @userType = CASE @userTypeId
WHEN 1 THEN 'Admin'
WHEN 2 THEN 'User'
ELSE 'Unknown'
END;
SELECT @userType;
Searched CASE
CASE
WHEN BooleanExpression1 THEN Result1
WHEN BooleanExpression2 THEN Result2
…
ELSE Result
END
DECLARE @userTypeId INT = 2;
DECLARE @userType VARCHAR(100);
SET @userType = CASE
WHEN @userTypeId = 1 THEN 'Admin'
WHEN @userTypeId = 2 THEN 'User'
ELSE 'Unknown'
END;
SELECT @userType;
Alternatively, we can also do:
DECLARE @inputNumber INT = 2
DECLARE @result NVARCHAR(MAX);
SELECT
@result =
CASE
WHEN ISNUMERIC(@inputNumber) = 1 AND @inputNumber % 2 = 0 THEN 'Even'
WHEN ISNUMERIC(@inputNumber) = 1 AND @inputNumber % 2 = 1 THEN 'Odd'
ELSE 'Not Number'
END;
SELECT @result AS Result;
With Variable
Use Like Switch
DECLARE @userTypeId INT = 2;
DECLARE @userType VARCHAR(100);
SET @userType = CASE @userTypeId
WHEN 1 THEN 'Admin'
WHEN 2 THEN 'User'
ELSE 'Unknown'
END;
SELECT @userType;
Multiple Compare
DECLARE @inputNumber INT = 2
DECLARE @result NVARCHAR(MAX);
SELECT
@result =
CASE
WHEN ISNUMERIC(@inputNumber) = 1 AND @inputNumber % 2 = 0 THEN 'Even'
WHEN ISNUMERIC(@inputNumber) = 1 AND @inputNumber % 2 = 1 THEN 'Odd'
ELSE 'Not Number'
END;
SELECT @result AS Result;
With SELECT Statement
Use Like Switch
SELECT
Id,
CASE Id
WHEN 1 THEN 'Admin'
WHEN 2 THEN 'User'
ELSE 'Anonymous'
END
FROM (
VALUES (1), (2), (NULL)
) AS Roles(Id)
Multiple Compare
SELECT
NumberValue,
CASE
WHEN ISNUMERIC(NumberValue) = 1 AND NumberValue % 2 = 0 THEN 'Even'
WHEN ISNUMERIC(NumberValue) = 1 AND NumberValue % 2 = 1 THEN 'Odd'
ELSE 'Not Number'
END
FROM(
VALUES ('1'), ('2'), ('A'), (NULL)
) AS NumberList(NumberValue)
With WHERE Clause
Here are our tables and data:
DECLARE @tblUserPoints TABLE
(
Name VARCHAR(100),
UserType VARCHAR(100),
Points INT
);
INSERT
INTO @tblUserPoints
VALUES
('Dan', 'Sa', 90000),
('Dan1', 'Sa', 80000),
('Ben', 'Admin', 70000),
('Ben1', 'Admin', 60000),
('Kim', 'User', 50000),
('Kim1', 'User', 40000);
CASE Instead of OR
Here is an example of regular WHERE
condition query:
SELECT *
FROM @tblUserPoints
WHERE (UserType = 'Sa' AND Points > 80000)
OR (UserType = 'Admin' AND Points > 60000)
OR (UserType = 'User' AND Points > 40000)
Rewriting above query using CASE
:
SELECT *
FROM @tblUserPoints
WHERE (
CASE
WHEN UserType = 'Sa' AND Points > 80000 THEN 1
WHEN UserType = 'Admin' AND Points > 60000 THEN 1
WHEN UserType = 'User' AND Points > 40000 THEN 1
ELSE NULL
END
) IS NOT NULL
The same way we can do things with AND
conditions.
Switch Between Conditions Depending On Flag
Here, depending on @flag
, the value we are actually switching between WHERE
condition:
DECLARE @flag VARCHAR(50);
SET @flag = 'Good';
SELECT *
FROM @tblUserPoints
WHERE (
CASE
WHEN @flag = 'Best' AND Points >= 80000 THEN 1
WHEN @flag = 'Better' AND Points >= 60000 AND Points < 80000 THEN 1
WHEN @flag = 'Good' AND Points >= 40000 AND Points < 60000 THEN 1
ELSE NULL
END
) IS NOT NULL
With JOIN and ON Clause
Our tables and data:
DECLARE @tblReputationTotal TABLE
(
TotalPoint INT NULL,
Reputation VARCHAR(100)
);
DECLARE @tblReputation TABLE
(
Point INT NULL,
RankPosition INT NULL,
Rating INT NULL,
Reputation VARCHAR(100)
);
DECLARE @tblUserPoint TABLE
(
Name VARCHAR(100),
UserType VARCHAR(100),
Point INT NULL,
RankPosition INT NULL,
Rating INT NULL
);
INSERT
INTO @tblReputationTotal (TotalPoint, Reputation)
VALUES
(90000, 'Best'),
(70000, 'Better'),
(50000, 'Good');
INSERT
INTO @tblReputation (Point, RankPosition, Rating, Reputation)
VALUES
(90000, NULL, NULL, 'Good Sa'),
(NULL, 70000, NULL, 'Good Admin'),
(NULL, NULL, 50000, 'Good User');
INSERT
INTO @tblUserPoint (Name, UserType, Point, RankPosition, Rating)
VALUES
('Dan', 'Sa', 90000, NULL, NULL),
('Dan1', 'Sa', 80000, NULL, NULL),
('Ben', 'Admin', NULL, 70000, NULL),
('Ben1', 'Admin', NULL, 60000, NULL),
('Kim', 'User', NULL, NULL, 50000),
('Kim1', 'User', NULL, NULL, 40000);
Here, depending on UserType
column value, we are selecting join
column:
SELECT u.*, r.Reputation
FROM @tblUserPoint AS u
JOIN @tblReputation AS r
ON CASE
WHEN u.UserType = 'Sa' AND u.Point = r.Point THEN 1
WHEN u.UserType = 'Admin' AND u.RankPosition = r.RankPosition THEN 1
WHEN u.UserType = 'User' AND u.Rating = r.Rating THEN 1
ELSE 0
END = 1;
Alternatively, we can also do:
SELECT u.*, r.Reputation
FROM @tblReputationTotal AS r
JOIN @tblUserPoint AS u
ON r.TotalPoint =
CASE
WHEN u.UserType = 'Sa' THEN u.Point
WHEN u.UserType = 'Admin' THEN u.RankPosition
WHEN u.UserType = 'User' THEN u.Rating
ELSE 0
END
With Update
DECLARE @tblBalance TABLE (Amount INT NULL, NumberType VARCHAR(100) NULL);
INSERT INTO @tblBalance(Amount) VALUES (1), (2), (3), (4), (NULL);
UPDATE @tblBalance
SET NumberType = CASE
WHEN Amount % 2 = 1 THEN 'Odd'
WHEN Amount % 2 = 0 THEN 'Even'
ELSE 'Null Value'
END;
SELECT * FROM @tblBalance;
With ORDER BY
Our tables and data:
DECLARE @tblEmployee TABLE
(
Id INT,
UserName VARCHAR(100),
Email VARCHAR(100)
);
INSERT
INTO @tblEmployee (Id, UserName, Email)
VALUES
(1, 'Dan', 'Dan@gmail.com'),
(2, 'Hen', 'Han@gmail.com'),
(3, 'Ben', 'Ben@gmail.com');
DECLARE @orderFilter VARCHAR(100);
SET @orderFilter = 'LoginName';
To manage order
, we are using an order indicator flag @orderFilter
.
@orderFilter
will hold the expected column name or logic to be used for ordering a particular data set.
Different Columns But Same Order
Here, we are switching between columns UserName
or Email
or None('')
but using the same order DESC
:
SELECT *
FROM @tblEmployee
ORDER BY
(
CASE @orderFilter
WHEN 'LoginName' THEN UserName
WHEN 'Email' THEN Email
ELSE ''
END
) DESC,
Id ASC
Column Wise Order
It is a bit different from the previous example. Here, order
type can be specific to each column.
SELECT *
FROM @tblEmployee
ORDER BY
CASE WHEN @orderFilter = 'LoginName' THEN UserName END DESC,
CASE WHEN @orderFilter = 'Email' THEN Email END ASC,
Id ASC
UserName
will be ordered as DESC
or Email
will be ordered as ASC
depending on the column selection flag @orderFilter
value.
Others
Limitations
OR
is not supported inside the boolean expression, instead of OR
use IN()
- Avoid nested
CASE
, SQL Server allows for only 10 levels of nesting in CASE
expressions. Instead use more WHEN
References
History
- 5th July, 2022: Initial version