Reputation: 4099
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?
Upvotes: 5
Views: 31662
Reputation: 1362
As Ganesh suggested in a comment, I recommend creating a mapping table for this and just do lookups. Much easier to interpet, maintain, and scale - all with better performance.
Upvotes: 0
Reputation: 6729
Hope this will help you
SELECT userid
,(CASE flag WHEN 1 THEN 'Apple' WHEN 2 THEN 'Pear' WHEN 3 THEN '..etc' END ) as snack
,(CASE flag WHEN 1 THEN 'Milk' WHEN 2 THEN 'Cola' WHEN 3 THEN '..etc' END ) as drink
FROM (
SELECT userid
,( CASE WHEN name IN ('A', 'B') THEN 1
WHEN name IN ('C', 'D') THEN 2
WHEN name IN ('X', 'Y') THEN 3
ELSE 0 END ) AS flag
FROM table ) t
Upvotes: 1
Reputation: 460208
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.
Upvotes: 2
Reputation: 69789
When doing things like this I tend to use a join with a table valued constructor:
SELECT t.UserID,
s.Snack,
s.Drink
FROM Table AS T
LEFT JOIN
(VALUES
(1, 'Apple', 'Milk'),
(2, 'Pear', 'Cola')
) AS s (Condition, Snack, Drink)
ON s.Condition = CASE
WHEN t.name IN ('A', 'B') THEN 1
WHEN t.name IN ('C', 'D') THEN 2
END;
I find this to be the most flexible if I need to add further conditions, or columns.
Or more verbose, but also more flexible:
SELECT t.UserID,
s.Snack,
s.Drink
FROM Table AS T
LEFT JOIN
(VALUES
('A', 'Apple', 'Milk'),
('B', 'Apple', 'Milk'),
('C', 'Pear', 'Cola'),
('D', 'Pear', 'Cola')
) AS s (Name, Snack, Drink)
ON s.Name= t.name;
Upvotes: 5