Note that there are some explanatory texts on larger screens.

plurals
  1. POSimplifying (aliasing) T-SQL CASE statements. Any improvement possible?
    primarykey
    data
    text
    <p>As you can see, this sucks big time. Any alternative? I've tried using the column alias in the group by clause to no avail.</p> <pre><code>select count(callid) , case when callDuration &gt; 0 and callDuration &lt; 30 then 1 when callDuration &gt;= 30 and callDuration &lt; 60 then 2 when callDuration &gt;= 60 and callDuration &lt; 120 then 3 when callDuration &gt;= 120 and callDuration &lt; 180 then 4 when callDuration &gt;= 180 and callDuration &lt; 240 then 5 when callDuration &gt;= 240 and callDuration &lt; 300 then 6 when callDuration &gt;= 300 and callDuration &lt; 360 then 7 when callDuration &gt;= 360 and callDuration &lt; 420 then 8 when callDuration &gt;= 420 and callDuration &lt; 480 then 9 when callDuration &gt;= 480 and callDuration &lt; 540 then 10 when callDuration &gt;= 540 and callDuration &lt; 600 then 11 when callDuration &gt;= 600 then 12 end as duration from callmetatbl where programid = 1001 and callDuration &gt; 0 group by case when callDuration &gt; 0 and callDuration &lt; 30 then 1 when callDuration &gt;= 30 and callDuration &lt; 60 then 2 when callDuration &gt;= 60 and callDuration &lt; 120 then 3 when callDuration &gt;= 120 and callDuration &lt; 180 then 4 when callDuration &gt;= 180 and callDuration &lt; 240 then 5 when callDuration &gt;= 240 and callDuration &lt; 300 then 6 when callDuration &gt;= 300 and callDuration &lt; 360 then 7 when callDuration &gt;= 360 and callDuration &lt; 420 then 8 when callDuration &gt;= 420 and callDuration &lt; 480 then 9 when callDuration &gt;= 480 and callDuration &lt; 540 then 10 when callDuration &gt;= 540 and callDuration &lt; 600 then 11 when callDuration &gt;= 600 then 12 end </code></pre> <p>EDIT: I really meant to ask how to have a single case source, but case modifications are welcome anyway (although less useful because the intervals probably will be modified and might even be automatically generated). </p> <p>As has been considered by some people, callDuration is indeed a float so some listed solutions are not valid for my use case, by leaving values out of the intervals.</p> <p>Lessons:</p> <ul> <li><p>Look for patterns in the case expression to reduce it if possible and worthwhile</p> <pre><code> case when callDuration &gt; 0 AND callDuration &lt; 30 then 1 when callDuration &gt; 600 then 12 else floor(callDuration/60) + 2 end end as duration </code></pre></li> <li><p>Use inline views to have a single source of the case</p> <pre><code>select count(d.callid), d.duration from ( select callid , case when callDuration &gt; 0 AND callDuration &lt; 30 then 1 when callDuration &gt; 600 then 12 else floor(callDuration/60) + 2 end end as duration from callmetatbl where programid = 1001 and callDuration &gt; 0 ) d group by d.duration </code></pre></li> <li><p>Or use common table expressions</p> <pre><code> with duration_case as ( select callid , case when callDuration &gt; 0 AND callDuration &lt; 30 then 1 when callDuration &gt; 600 then 12 else floor(callDuration/60) + 2 end end as duration from callmetatbl where programid = 1001 and callDuration &gt; 0 ) select count(callid), duration from duration_case group by duration </code></pre></li> <li><p>Or use an user defined function (no example so far :-) )</p></li> <li><p>Or use a lookup table and a join</p> <pre><code>DECLARE @t TABLE(durationFrom float, durationTo float, result INT) --populate table with values so the query works select count(callid) , COALESCE(t.result, 12) from callmetatbl JOIN @t AS t ON callDuration &gt;= t.durationFrom AND callDuration &lt; t.durationTo where programid = 1001 and callDuration &gt; 0 </code></pre></li> </ul> <p>Thanks to everybody and I'm having a very difficult time choosing an accepted answer, as many covered different parts of the question (and I was there thinking it was a simple question with a straightforward answer :-), sorry for the confusion).</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. COif the question is "how do I alias a complex expression so I can reference it in a GROUP BY clause", one approach is to use an inline view (see my answer), or a view definition stored in the database). the _other_ question (everyone else seems to be answering) is "how do I simplify this particular expression", there's several approaches to that as well.
      singulars
    2. CO@vinko: i've updated my answer to include an example user defined function (just a scalar function to replace the inline expression). a table valued function could be used to return a lookup table... that's a workable approach as well. BE CAREFUL of gaps and overlaps using lookup tables and join conditions (the potential for rows to be dropped and/or duplicated.) Consider what's going to need to be TESTED vs. the need for flexibility. (In my experience, it takes more effort to _test_ code than it does to _write_ code.)
      singulars
    3. CO@vinko: ALSO consider specifying each "breakpoint" value only once (use only one bound, and the guarantee of an early return when a condition is satisfied.) I infer the specification that every callDuration (>0) should fall into a bucket, and not be lost in a gap between two buckets.
      singulars
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload