CASE

Other topics

Remarks:

The simple CASE expression returns the first result whose compareX value is equal to the input_expression.

The searched CASE expression returns the first result whose conditionX is true.

Searched CASE in SELECT (Matches a boolean expression)

The searched CASE returns results when a boolean expression is TRUE.

(This differs from the simple case, which can only check for equivalency with an input.)

SELECT Id, ItemId, Price,
  CASE WHEN Price < 10 THEN 'CHEAP'
       WHEN Price < 20 THEN 'AFFORDABLE'
       ELSE 'EXPENSIVE'
  END AS PriceRating
FROM ItemSales
IdItemIdPricePriceRating
110034.5EXPENSIVE
21452.3CHEAP
310034.5EXPENSIVE
410034.5EXPENSIVE
514510AFFORDABLE

Use CASE to COUNT the number of rows in a column match a condition.

Use Case

CASE can be used in conjunction with SUM to return a count of only those items matching a pre-defined condition. (This is similar to COUNTIF in Excel.)

The trick is to return binary results indicating matches, so the "1"s returned for matching entries can be summed for a count of the total number of matches.

Given this table ItemSales, let's say you want to learn the total number of items that have been categorized as "Expensive":

IdItemIdPricePriceRating
110034.5EXPENSIVE
21452.3CHEAP
310034.5EXPENSIVE
410034.5EXPENSIVE
514510AFFORDABLE

Query

SELECT 
    COUNT(Id) AS ItemsCount,
    SUM ( CASE 
            WHEN PriceRating = 'Expensive' THEN 1
            ELSE 0
          END
        ) AS ExpensiveItemsCount
FROM ItemSales 

Results:

ItemsCountExpensiveItemsCount
53

Alternative:

SELECT 
    COUNT(Id) as ItemsCount,
    SUM (
        CASE PriceRating 
            WHEN 'Expensive' THEN 1
            ELSE 0
        END
       ) AS ExpensiveItemsCount
FROM ItemSales 

Shorthand CASE in SELECT

CASE's shorthand variant evaluates an expression (usually a column) against a series of values. This variant is a bit shorter, and saves repeating the evaluated expression over and over again. The ELSE clause can still be used, though:

SELECT Id, ItemId, Price,
  CASE Price WHEN 5  THEN 'CHEAP'
             WHEN 15 THEN 'AFFORDABLE'
             ELSE         'EXPENSIVE'
  END as PriceRating
FROM ItemSales

A word of caution. It's important to realize that when using the short variant the entire statement is evaluated at each WHEN. Therefore the following statement:

SELECT 
    CASE ABS(CHECKSUM(NEWID())) % 4
        WHEN 0 THEN 'Dr'
        WHEN 1 THEN 'Master'
        WHEN 2 THEN 'Mr'
        WHEN 3 THEN 'Mrs'
    END

may produce a NULL result. That is because at each WHEN NEWID() is being called again with a new result. Equivalent to:

SELECT 
    CASE 
        WHEN ABS(CHECKSUM(NEWID())) % 4 = 0 THEN 'Dr'
        WHEN ABS(CHECKSUM(NEWID())) % 4 = 1 THEN 'Master'
        WHEN ABS(CHECKSUM(NEWID())) % 4 = 2 THEN 'Mr'
        WHEN ABS(CHECKSUM(NEWID())) % 4 = 3 THEN 'Mrs'
    END

Therefore it can miss all the WHEN cases and result as NULL.

CASE in a clause ORDER BY

We can use 1,2,3.. to determine the type of order:

SELECT * FROM DEPT
ORDER BY
CASE DEPARTMENT
      WHEN 'MARKETING' THEN  1
      WHEN 'SALES' THEN 2
      WHEN 'RESEARCH' THEN 3
      WHEN 'INNOVATION' THEN 4
      ELSE        5
      END,
      CITY
IDREGIONCITYDEPARTMENTEMPLOYEES_NUMBER
12New EnglandBostonMARKETING9
15WestSan FranciscoMARKETING12
9MidwestChicagoSALES8
14Mid-AtlanticNew YorkSALES12
5WestLos AngelesRESEARCH11
10Mid-AtlanticPhiladelphiaRESEARCH13
4MidwestChicagoINNOVATION11
2MidwestDetroitHUMAN RESOURCES9

Using CASE in UPDATE

sample on price increases:

UPDATE ItemPrice
SET Price = Price *
  CASE ItemId
    WHEN 1 THEN 1.05
    WHEN 2 THEN 1.10
    WHEN 3 THEN 1.15
    ELSE 1.00
  END

CASE use for NULL values ​​ordered last

in this way '0' representing the known values ​​are ranked first, '1' representing the NULL values ​​are sorted by the last:

SELECT ID
      ,REGION
      ,CITY
      ,DEPARTMENT
      ,EMPLOYEES_NUMBER
  FROM DEPT
  ORDER BY 
  CASE WHEN REGION IS NULL THEN 1 
  ELSE 0
  END, 
  REGION
IDREGIONCITYDEPARTMENTEMPLOYEES_NUMBER
10Mid-AtlanticPhiladelphiaRESEARCH13
14Mid-AtlanticNew YorkSALES12
9MidwestChicagoSALES8
12New EnglandBostonMARKETING9
5WestLos AngelesRESEARCH11
15NULLSan FranciscoMARKETING12
4NULLChicagoINNOVATION11
2NULLDetroitHUMAN RESOURCES9

CASE in ORDER BY clause to sort records by lowest value of 2 columns

Imagine that you need sort records by lowest value of either one of two columns. Some databases could use a non-aggregated MIN() or LEAST() function for this (... ORDER BY MIN(Date1, Date2)), but in standard SQL, you have to use a CASE expression.

The CASE expression in the query below looks at the Date1 and Date2 columns, checks which column has the lower value, and sorts the records depending on this value.

Sample data

IdDate1Date2
12017-01-012017-01-31
22017-01-312017-01-03
32017-01-312017-01-02
42017-01-062017-01-31
52017-01-312017-01-05
62017-01-042017-01-31

Query

SELECT Id, Date1, Date2
FROM YourTable
ORDER BY CASE 
           WHEN COALESCE(Date1, '1753-01-01') < COALESCE(Date2, '1753-01-01') THEN Date1 
           ELSE Date2 
         END

Results

IdDate1Date2
12017-01-012017-01-31
32017-01-312017-01-02
22017-01-312017-01-03
62017-01-042017-01-31
52017-01-312017-01-05
42017-01-062017-01-31

Explanation

As you see row with Id = 1 is first, that because Date1 have lowest record from entire table 2017-01-01, row where Id = 3 is second that because Date2 equals to 2017-01-02 that is second lowest value from table and so on.

So we have sorted records from 2017-01-01 to 2017-01-06 ascending and no care on which one column Date1 or Date2 are those values.

Syntax:

  • CASE input_expression
     WHEN compare1 THEN result1
    [WHEN compare2 THEN result2]...
    [ELSE resultX]
    END
  • CASE
     WHEN condition1 THEN result1
    [WHEN condition2 THEN result2]...
    [ELSE resultX]
    END

Contributors

Topic Id: 456

Example Ids: 1508,1612,1915,10805,13184,15268,30973

This site is not affiliated with any of the contributors.