【发布时间】:2009-06-04 17:01:40
【问题描述】:
如您所见,这很糟糕。有什么选择吗?我尝试在 group by 子句中使用列别名,但无济于事。
select count(callid) ,
case
when callDuration > 0 and callDuration < 30 then 1
when callDuration >= 30 and callDuration < 60 then 2
when callDuration >= 60 and callDuration < 120 then 3
when callDuration >= 120 and callDuration < 180 then 4
when callDuration >= 180 and callDuration < 240 then 5
when callDuration >= 240 and callDuration < 300 then 6
when callDuration >= 300 and callDuration < 360 then 7
when callDuration >= 360 and callDuration < 420 then 8
when callDuration >= 420 and callDuration < 480 then 9
when callDuration >= 480 and callDuration < 540 then 10
when callDuration >= 540 and callDuration < 600 then 11
when callDuration >= 600 then 12
end as duration
from callmetatbl
where programid = 1001 and callDuration > 0
group by case
when callDuration > 0 and callDuration < 30 then 1
when callDuration >= 30 and callDuration < 60 then 2
when callDuration >= 60 and callDuration < 120 then 3
when callDuration >= 120 and callDuration < 180 then 4
when callDuration >= 180 and callDuration < 240 then 5
when callDuration >= 240 and callDuration < 300 then 6
when callDuration >= 300 and callDuration < 360 then 7
when callDuration >= 360 and callDuration < 420 then 8
when callDuration >= 420 and callDuration < 480 then 9
when callDuration >= 480 and callDuration < 540 then 10
when callDuration >= 540 and callDuration < 600 then 11
when callDuration >= 600 then 12
end
编辑: 我真的想问如何拥有单个案例源,但无论如何都欢迎案例修改(尽管不太有用,因为间隔可能会被修改,甚至可能会自动生成)。
正如某些人所考虑的那样, callDuration 确实是一个浮点数,因此某些列出的解决方案对我的用例无效,因为将值排除在间隔之外。
课程:
-
在 case 表达式中寻找模式以减少它,如果可能且值得的话
case when callDuration > 0 AND callDuration < 30 then 1 when callDuration > 600 then 12 else floor(callDuration/60) + 2 end end as duration -
使用内联视图来获得案例的单一来源
select count(d.callid), d.duration from ( select callid , case when callDuration > 0 AND callDuration < 30 then 1 when callDuration > 600 then 12 else floor(callDuration/60) + 2 end end as duration from callmetatbl where programid = 1001 and callDuration > 0 ) d group by d.duration -
或者使用公用表表达式
with duration_case as ( select callid , case when callDuration > 0 AND callDuration < 30 then 1 when callDuration > 600 then 12 else floor(callDuration/60) + 2 end end as duration from callmetatbl where programid = 1001 and callDuration > 0 ) select count(callid), duration from duration_case group by duration 或者使用用户定义的函数(目前没有例子:-))
-
或者使用查找表和连接
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 >= t.durationFrom AND callDuration < t.durationTo where programid = 1001 and callDuration > 0
感谢大家,我很难选择一个可以接受的答案,因为许多人涵盖了问题的不同部分(我当时认为这是一个简单的问题,答案很简单:-),抱歉混乱)。
【问题讨论】:
-
如果问题是“我如何为复杂表达式设置别名,以便可以在 GROUP BY 子句中引用它”,一种方法是使用内联视图(请参阅我的答案)或视图定义存储在数据库中)。 other 问题(其他人似乎都在回答)是“我如何简化这个特定的表达式”,也有几种方法。
-
@vinko:我已经更新了我的答案以包含一个示例用户定义函数(只是一个标量函数来替换内联表达式)。表值函数可用于返回查找表......这也是一种可行的方法。使用查找表和连接条件(行被删除和/或重复的可能性)注意间隙和重叠。考虑需要测试的内容与灵活性的需要。 (根据我的经验,测试代码比编写代码需要更多的努力。)
-
@vinko:还考虑只指定每个“断点”值一次(只使用一个边界,并保证在满足条件时提前返回。)我推断每个 callDuration (> 0) 应该落入一个桶中,而不是丢失在两个桶之间的空隙中。
标签: sql-server tsql case