Vin*_*vic 5 t-sql sql-server case
正如你所看到的,这很糟糕.还有其他选择 我尝试在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
Run Code Online (Sandbox Code Playgroud)
编辑:我真的想问如何有一个案例源,但无论如何都欢迎案例修改(虽然不太有用,因为间隔可能会被修改,甚至可能自动生成).
正如一些人所考虑的那样,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
Run Code Online (Sandbox Code Playgroud)使用内联视图来拥有案例的单一来源
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
Run Code Online (Sandbox Code Playgroud)或者使用公用表表达式
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
Run Code Online (Sandbox Code Playgroud)或者使用用户定义的函数(到目前为止没有例子:-))
或者使用查找表和连接
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
Run Code Online (Sandbox Code Playgroud)感谢大家,我很难选择一个接受的答案,因为很多人都在讨论问题的不同部分(我在那里认为这是一个简单的问题,答案简单明了:-),对不起这个混乱).
你有没有理由不使用between?案例陈述本身并不太糟糕.如果你真的讨厌它,你可以将所有这些扔进桌子并映射它.
Durations
------------------
low high value
0 30 1
31 60 2
Run Code Online (Sandbox Code Playgroud)
等等...
(SELECT value FROM Durations WHERE callDuration BETWEEN low AND high) as Duration
Run Code Online (Sandbox Code Playgroud)
编辑:或者,在使用花车并且between变得麻烦的情况下.
(SELECT value FROM Durations WHERE callDuration >= low AND callDuration <= high) as Duration
Run Code Online (Sandbox Code Playgroud)
问:如何在GROUP BY子句中使用别名
一种方法是使用内联视图.[编辑] Remus Rusanu的答案(+1!)给出了一个公用表表达式的例子来完成同样的事情.[/编辑]
内联视图为您提供复杂表达式的简单"别名",然后您可以在外部查询中的GROUP BY子句中引用该表达式:
select count(d.callid)
, d.duration
from (select callid
, case
when callDuration >= 600 then 12
when callDuration >= 540 then 11
when callDuration >= 480 then 10
when callDuration >= 420 then 9
when callDuration >= 360 then 8
when callDuration >= 300 then 7
when callDuration >= 240 then 6
when callDuration >= 180 then 5
when callDuration >= 120 then 4
when callDuration >= 60 then 3
when callDuration >= 30 then 2
when callDuration > 0 then 1
--else null
end as duration
from callmetatbl
where programid = 1001
and callDuration > 0
) d
group by d.duration
Run Code Online (Sandbox Code Playgroud)
让我们打开它.
d)duration从d这应该足以回答你的问题.如果你正在寻找一个等价的替换表达式,tekBlues(+ 1!)中的那个是正确的答案(它适用于边界和非整数.)
使用tekBlues(+1!)的替换表达式:
select count(d.callid)
, d.duration
from (select callid
, case
when callduration >=30 and callduration<600
then floor(callduration/60)+2
when callduration>0 and callduration< 30
then 1
when callduration>=600
then 12
end as duration
from callmetatbl
where programid = 1001
and callDuration > 0
) d
group by d.duration
Run Code Online (Sandbox Code Playgroud)
(这应该足以回答你的问题了.)
[UPDATE:]示例用户定义的函数(内联CASE表达式的替换)
CREATE FUNCTION [dev].[udf_duration](@cd FLOAT)
RETURNS SMALLINT
AS
BEGIN
DECLARE @bucket SMALLINT
SET @bucket =
CASE
WHEN @cd >= 600 THEN 12
WHEN @cd >= 540 THEN 11
WHEN @cd >= 480 THEN 10
WHEN @cd >= 420 THEN 9
WHEN @cd >= 360 THEN 8
WHEN @cd >= 300 THEN 7
WHEN @cd >= 240 THEN 6
WHEN @cd >= 180 THEN 5
WHEN @cd >= 120 THEN 4
WHEN @cd >= 60 THEN 3
WHEN @cd >= 30 THEN 2
WHEN @cd > 0 THEN 1
--ELSE NULL
END
RETURN @bucket
END
select count(callid)
, [dev].[udf_duration](callDuration)
from callmetatbl
where programid = 1001
and callDuration > 0
group by [dev].[udf_duration](callDuration)
Run Code Online (Sandbox Code Playgroud)
注意:请注意,用户定义的函数会增加开销,并且(当然)会在另一个数据库对象上添加依赖项.
此示例函数等效于原始表达式.OP CASE表达式没有任何间隙,但它确实引用了每个"断点"两次,我更喜欢只测试下限.(CASE在满足条件时返回.反向执行测试可以使未处理的情况(<= 0或NULL)在没有测试的情况下通过,ELSE NULL不需要,但可以添加完整性.
额外细节
(请务必检查性能和优化程序计划,以确保它与原始程序相同(或者不会明显差于原始程序).过去,我在将谓词推入内联视图时遇到问题,看起来不看喜欢这样你的情况会有问题.)
存储的视图
请注意,内联视图也可以作为视图定义存储在数据库中.但除了从你的陈述中"隐藏"复杂的表达之外,没有理由这样做.
简化复杂的表达
使复杂表达式"更简单"的另一种方法是使用用户定义的函数.但是用户定义的函数会带来一系列问题(包括性能下降).
添加数据库"查找"表
一些答案建议在数据库中添加"查找"表.我不认为这是非常必要的.它可以做,当然,并可以使意义,如果你希望能够为获得不同的值duration从callDuration,对飞,不不必修改您的查询,而无需为运行任何DDL语句(如更改视图定义,或修改用户定义的函数).
通过连接到"查找"表,一个好处是您可以通过在"查找"表上执行DML操作来使查询返回不同的结果集.
但同样的优势实际上也可能是一个缺点.
如果利益实际上超过了下行,请仔细考虑.考虑新表对单元测试的影响,如何验证查找表的内容是否有效且未更改(任何重叠?任何间隙?),对代码的持续维护(由于额外的复杂性)的影响.
一些大的假设
这里给出的很多答案似乎都假设它callDuration是一个INTEGER数据类型.似乎他们忽略了它不是整数的可能性,但也许我错过了问题中的那个金块.
这是一个相当简单的测试用例来证明:
callDuration BETWEEN 0 AND 30
Run Code Online (Sandbox Code Playgroud)
是不是等同于
callDuration > 0 AND callDuration < 30
Run Code Online (Sandbox Code Playgroud)
案件可以这样写:
case
when callduration >=30 and callduration<600 then floor(callduration/60)+2
when callduration>0 and callduration< 30 then 1
when callduration>=600 then 12
end
Run Code Online (Sandbox Code Playgroud)
没有需要,用"callduration> 0"替换它
我喜欢之前给出的翻译表答案!这是最好的解决方案
| 归档时间: |
|
| 查看次数: |
5443 次 |
| 最近记录: |