Advertisement
Advertisement


SQL 'CASE WHEN x' vs. 'CASE x WHEN' with greater-than condition?


Question

This is a questions about the two ways to use the SELECT CASE in MS SQL [CASE WHEN X = Y] and [CASE X WHEN Y]

I am trying to define buckets for a field based on its values. I would need to use ranges, so it is necessary to use the "<" or ">" identifiers.

As a simple example, I know it works like this:

SELECT CASE WHEN x < 0 THEN 'a' WHEN X > 100 THEN 'b' ELSE 'c' END

Now I have to write a lot of these, there will be more than 3 buckets and the field names are quite long, so this becomes very difficult to keep clean and easy to follow. I was hoping to use the other way of the select command but to me it looks like I can only use it with equals:

SELECT CASE X WHEN 0 then 'y' ELSE 'z' END

But how can I use this form to specify range conditions just as above? Something like:

SELECT CASE X WHEN < 0 THEN 'a' WHEN > 100 THEN 'b' ELSE "c" END

This one does not work.

Thank You!

2013/09/30
1
3
9/30/2013 6:18:12 PM

Accepted Answer

As an alternative approach, remember that it is possible to do math on the value that is the input to the "simple" CASE statement. I often use ROUND for this purpose, like this:

SELECT 
  CASE ROUND(X, -2, 1)
    WHEN 0   THEN 'b' -- 0-99
    WHEN 100 THEN 'c' -- 100-199
    ELSE 'a'          -- 200+
  END

Since your example includes both positive and negative open-ended ranges, this approach may not work for you.

Still another approach: if you are only thinking about readability in the SELECT statement, you could write a scalar-valued function to hide all the messiness:

CREATE FUNCTION dbo.ufn_SortValuesIntoBuckets (@inputValue INT) RETURNS VARCHAR(10) AS
BEGIN
    DECLARE @outputValue VARCHAR(10);

    SELECT @outputValue = 
        CASE WHEN @inputValue < 0 THEN 'a'
             WHEN @inputValue BETWEEN 0 AND 100 THEN 'b'
             WHEN @inputValue > 100 THEN 'c'
        END;

    RETURN @outputValue;
END;
GO

So now your SELECT statement is just:

SELECT dbo.ufn_SortValuesIntoBuckets(X); 

One final consideration: I have often found, during benchmark testing, that the "searched" form (which you are trying to avoid) actually has better performance than the "simple" form, depending how many CASEs you have. So if performance is a consideration, it might be worth your while to do a little benchmarking before you change things around too much.

2014/10/31
3
10/31/2014 8:08:30 PM

There is no such "third form" of the CASE - only the searched and the simple cases are supported *.

You need to use the searched kind (i.e. with separate conditions) even though the variable to which you apply the condition is always the same.

If you are looking to avoid repetition in your SQL when X represents a complex expression, use WITH clause or a nested query to assign a name to the expression that you are selecting.


* The official name of your first example is "searched CASE expression"; your second example is called the "simple CASE expression".

2013/09/30

It won't look so bad using BETWEENs:

SELECT CASE
WHEN X < 0 THEN 'a'
WHEN X BETWEEN 0   AND 100 THEN 'b' 
WHEN X BETWEEN 100 AND 200 THEN 'c' 
ELSE 'd' END
2013/09/30

That is actually very interesting question. It resembles C# 9.0 relational pattern

SELECT CASE X WHEN < 0 THEN 'a' 
              WHEN > 100 THEN 'b' 
              ELSE 'c' 
        END

C# 9.0
DeliveryTruck t when t.GrossWeightClass switch
{
    > 5000 => 10.00m + 5.00m,
    < 3000 => 10.00m - 2.00m,
    _ => 10.00m,
},

SQL CASE expression as mentioned in previous answers has two forms: simple and searched.

But SQL standard defines also SQL:2003 Extended CASE expression(F262). This feature is barely adopted by major vendors.

case — Conditional Expressions by Markus Winand

The so-called extended case accepts a comparison operator right after when and thus lifts the limitation that simple case always uses equals (=) comparisons. The following example uses the less than operator (<) to map values into intervals. It also relies on the precedence of when clauses: the first true condition wins.

CASE x WHEN < 0   THEN '< 0'
       WHEN < 10  THEN '[0, 10['
       WHEN < 100 THEN '[10, 100['
       ELSE '>100'
END
2020/05/21