I'm writing an SQL Query, where a few of the columns returned need to be calculated depending on quite a lot of conditions. I'm currently using nested case statements, but its getting messy. Is there a better (more organised and/or readable) way? (I am using Microsoft SQL Server, 2005) A simplified example:
SELECT col1, col2, col3, CASE WHEN condition THEN CASE WHEN condition1 THEN CASE WHEN condition2 THEN calculation1 ELSE calculation2 END ELSE CASE WHEN condition2 THEN calculation3 ELSE calculation4 END END ELSE CASE WHEN condition1 THEN CASE WHEN condition2 THEN calculation5 ELSE calculation6 END ELSE CASE WHEN condition2 THEN calculation7 ELSE calculation8 END END END AS 'calculatedcol1', col4, col5 -- etc FROM table
78.6k 17 17 gold badges 154 154 silver badges 201 201 bronze badges
asked Feb 3, 2009 at 1:39
5,793 11 11 gold badges 39 39 silver badges 43 43 bronze badges
Hi, did you use a tool (like SQLinForm) to indent the nested queries so nicely?
Commented Jun 1, 2013 at 13:20
Appreciate you teaching me a nicer formatting method for nested CASE WHEN
Commented Jan 8, 2015 at 6:39
There are certainly times when this would be efficient and helpful, but in general, I like to keep logic away from my SQL queries. Just a tip for posterity.
Commented Jul 13, 2018 at 19:50You could try some sort of COALESCE trick, eg:
SELECT COALESCE( CASE WHEN condition1 THEN calculation1 ELSE NULL END, CASE WHEN condition2 THEN calculation2 ELSE NULL END, etc. )answered Feb 3, 2009 at 1:44 4,992 3 3 gold badges 28 28 silver badges 35 35 bronze badges
Nice, I just tested to ensure that it short-circuits, and was suprised to find that it does. So if condition1 checked for a divide by zero, it appears that it's safe to do it in condition2. Not sure if this is guaranteed.
Commented Feb 3, 2009 at 3:34 One catch is that if one of your cases legitimately wants to return a NULL, it's no longer possible. Commented Feb 5, 2009 at 3:56This is a great trick, but keep in mind that it may not perform as well as using CASE statements alone. This is "documented" in the Community Additions section here - msdn.microsoft.com/en-us/library/ms190349.aspx. My DBA just put the hammer down when I implemented this solution.
Commented Jan 25, 2013 at 16:54 When is this better than just a case statement (@beach's answer)? Commented Apr 4, 2014 at 17:28How to rename a column in this answer.. e.g if I want to rename 'calculation1' to 'CAL1'. How is it possible syntactically ?
Commented Apr 12, 2017 at 6:38Wrap all those cases into one.
SELECT col1, col2, col3, CASE WHEN condition1 THEN calculation1 WHEN condition2 THEN calculation2 WHEN condition3 THEN calculation3 WHEN condition4 THEN calculation4 WHEN condition5 THEN calculation5 ELSE NULL END AS 'calculatedcol1', col4, col5 -- etc FROM table
answered Jul 12, 2012 at 17:17
3,357 2 2 gold badges 24 24 silver badges 20 20 bronze badges
See this late answer below which is a mere copy but stresses that you do not have to write ELSE NULL which sometimes comes in handy.
Commented Aug 6 at 18:03You can combine multiple conditions to avoid the situation:
CASE WHEN condition1 = true AND condition2 = true THEN calculation1 WHEN condition1 = true AND condition2 = false THEN calculation2 ELSE 'what so ever' END,
299 2 2 silver badges 12 12 bronze badges
answered May 31, 2013 at 11:45
633 6 6 silver badges 14 14 bronze badges
I personally do it this way, keeping the embedded CASE expressions confined. I'd also put comments in to explain what is going on. If it is too complex, break it out into function.
SELECT col1, col2, col3, CASE WHEN condition THEN CASE WHEN condition1 THEN CASE WHEN condition2 THEN calculation1 ELSE calculation2 END ELSE CASE WHEN condition2 THEN calculation3 ELSE calculation4 END END ELSE CASE WHEN condition1 THEN CASE WHEN condition2 THEN calculation5 ELSE calculation6 END ELSE CASE WHEN condition2 THEN calculation7 ELSE calculation8 END END AS 'calculatedcol1', col4, col5 -- etc FROM table
answered Feb 3, 2009 at 1:58
8,570 4 4 gold badges 31 31 silver badges 26 26 bronze badges
Here's a simple solution to the nested "Complex" case statment: --Nested Case Complex Expression
select datediff(dd,Invdate,'2009/01/31')+1 as DaysOld, case when datediff(dd,Invdate,'2009/01/31')+1 >150 then 6 else case when datediff(dd,Invdate,'2009/01/31')+1 >120 then 5 else case when datediff(dd,Invdate,'2009/01/31')+1 >90 then 4 else case when datediff(dd,Invdate,'2009/01/31')+1 >60 then 3 else case when datediff(dd,Invdate,'2009/01/31')+1 >30 then 2 else case when datediff(dd,Invdate,'2009/01/31')+1 >30 then 1 end end end end end end as Bucket from rm20090131atb
Just make sure you have an end statement for every case statement
1,600 2 2 gold badges 18 18 silver badges 35 35 bronze badges answered Jul 17, 2009 at 14:13 Jims2885 Jims2885 You may want to format your answer if you want it to be read by others. Commented May 17, 2010 at 5:20 how is this an improvement on the method used in the original question? Commented Feb 9, 2021 at 23:40a user-defined function may server better, at least to hide the logic - esp. if you need to do this in more than one query
answered Feb 3, 2009 at 1:42 Steven A. Lowe Steven A. Lowe 61k 19 19 gold badges 133 133 silver badges 204 204 bronze badgesWe can combine multiple conditions together to reduce the performance overhead.
Let there are three variables a b c on which we want to perform cases. We can do this as below:
CASE WHEN a = 1 AND b = 1 AND c = 1 THEN '1' WHEN a = 0 AND b = 0 AND c = 1 THEN '0' ELSE '0' END,
answered Mar 9, 2015 at 8:07
Sanjeev Singh Sanjeev Singh
4,046 3 3 gold badges 35 35 silver badges 38 38 bronze badges
This is the same as the [2 years older answer]( stackoverflow.com/a/16856534/11154841).
Commented Aug 6 at 17:57
I went through this and found all the answers super cool, however wants to add to answer given by @deejers
SELECT col1, col2, col3, CASE WHEN condition1 THEN calculation1 WHEN condition2 THEN calculation2 WHEN condition3 THEN calculation3 WHEN condition4 THEN calculation4 WHEN condition5 THEN calculation5 END AS 'calculatedcol1', col4, col5 -- etc FROM table
you can make ELSE optional as its not mandatory, it is very helpful in many scenarios.
answered Oct 16, 2017 at 10:50 user3065757 user3065757 493 1 1 gold badge 5 5 silver badges 14 14 bronze badgesright, you just drop here the line ELSE NULL , but that is still good to keep in mind that you can do it, which the other answer does not tell.
Commented Aug 6 at 18:01This example might help you, the picture shows how SQL case statement will look like when there are if and more than one inner if loops
answered Jun 24, 2019 at 10:14 279 1 1 gold badge 2 2 silver badges 9 9 bronze badgesPlease put the text of the code instead of screenshots because screenshots are hard to reuse or confirm.
Commented Feb 4, 2021 at 10:16@Manik Not instead, but on top. The image is good to read, that can stay, and the code on top is good for internet searching and copying.
Commented Aug 6 at 17:59Less complex format. Make sure keep the indentation as it is to not to be lost in ENDs.
SELECT CASE WHEN 1=1 THEN CASE WHEN 11=11 THEN CASE WHEN 111=111 THEN '1-11-111' END WHEN 12=12 THEN CASE WHEN 122=122 THEN '1-12-122' END WHEN 13=13 THEN CASE WHEN 133=133 THEN '1-13-133' END END ELSE CASE WHEN 2=2 THEN CASE WHEN 21=21 THEN CASE WHEN 211=211 THEN '2-21-211' END WHEN 22=22 THEN CASE WHEN 222=222 THEN '2-22-222' END END ELSE CASE WHEN 3=3 THEN CASE WHEN 31=31 THEN CASE WHEN 311=311 THEN '3-31-311' END WHEN 32=32 THEN CASE WHEN 322=322 THEN '3-32-322' END END ELSE CASE WHEN 4=4 THEN CASE WHEN 41=41 THEN CASE WHEN 411=411 THEN '4-41-411' END WHEN 42=42 THEN CASE WHEN 412=412 THEN '4-42-412' END END ELSE CASE WHEN 51=51 THEN CASE WHEN 511=511 THEN '51-511' END WHEN 52=52 THEN CASE WHEN 512=512 THEN '52-512' END WHEN 53=53 THEN CASE WHEN 513=513 THEN '53-513' END WHEN 54=54 THEN CASE WHEN 514=514 THEN '54-514' END END END END END END AS Sku FROM YourTable