Search code examples
sqlsql-servercase-statement

How to assign multiple values in CASE statement?


I need to assign two values to my select based on a CASE statement. In pseudo:

select
    userid
  , case
        when name in ('A', 'B') then 'Apple'
        when name in ('C', 'D') then 'Pear'
    end as snack
from
    table
;

I am assigning a value for snack. But lets say I also want to assign a value for another variable, drink based on the same conditions. One way would be to repeat the above:

select
    userid
  , case
        when name in ('A', 'B') then 'Apple'
        when name in ('C', 'D') then 'Pear'
    end as snack
  , case
        when name in ('A', 'B') then 'Milk'
        when name in ('C', 'D') then 'Cola'
    end as drink
from
    table
;

However, if I have to assign more values based on the same conditions, say food, drink, room, etc. this code becomes hard to maintain.

Is there a better way of doing this? Can I put this in a SQL function, like you would normally do in another (scripting) language and if so, could you please explain how?


Solution

  • Functions destroy performance. But you could use a common-table-expression(cte):

    with cte as
    (
        Select IsNameInList1 = case when name in ('A', 'B') 
                               then 1 else 0 end,
               IsNameInList2 = case when name in ('C', 'D') 
                               then 1 else 0 end,
               t.*
        from table
    )
    select
        userid
      , case when IsNameInList1=1 then 'Apple'
             when IsNameInList2=1 then 'Pear'
        end as snack
      , case when IsNameInList1=1 then 'Milk'
             when IsNameInList2=1 then 'Cola'
        end as drink
    from
        cte
    ;
    

    On this way you have only one place to maintain.

    If query performance doesn't matter and you want to use a scalar valued function like this:

    CREATE FUNCTION [dbo].[IsNameInList1] 
    (
        @name varchar(100)
    )
    RETURNS bit
    AS
    BEGIN
    DECLARE @isNameInList bit
    
    BEGIN
        SET @isNameInList =  
        CASE WHEN @name in ('A', 'B')
        THEN 1
        ELSE 0 
        END
    END
    
     RETURN @isNameInList 
    END
    

    Then you can use it in your query in this way:

    select
        userid
      , case when dbo.IsNameInList1(name) = 1 then 'Apple'
             when dbo.IsNameInList2(name) = 1 then 'Pear'
        end as snack
    from
        table
    ;
    

    But a more efficient approach would be to use a real table to store them.