使用聚合函数时,SELECT with CASE失败

时间:2014-07-22 12:03:43

标签: sql sql-server tsql sql-server-2012

我有以下t-sql查询。

DECLARE @Test TABLE(
    Points INT
    ,PointsOf INT
)
INSERT INTO @Test
VALUES (3,12),(2,12),(3,12),(11,12),(12,12),(5,12),(0,12)

DECLARE @Decimal TINYINT = 2


SELECT  
    CASE @Decimal
        WHEN 0 THEN CAST(CAST(SUM(Points) AS DECIMAL(18,0)) / NULLIF(SUM(PointsOf), 0) * 100 AS DECIMAL(18,0))
        WHEN 1 THEN CAST(CAST(SUM(Points) AS DECIMAL(18,1)) / NULLIF(SUM(PointsOf), 0) * 100 AS DECIMAL(18,1))
        WHEN 2 THEN CAST(CAST(SUM(Points) AS DECIMAL(18,2)) / NULLIF(SUM(PointsOf), 0) * 100 AS DECIMAL(18,2))
    END  AS Score
FROM @Test

我有一个变量@Decimals。当变量为0时,我需要我的查询以XX格式返回分数,当它的XX.X格式为1时,以及XX.XX格式的2时。 这里发生的是CASE输入多个THEN子句。当执行上面的查询时,我得到44.86作为结果是正确的,但是当我将@Decimals valiable更改为0时,我得到结果44.00,这是incorect。它假设只返回44而没有小数。同样的事情发生在@Decimals为1时,当它必须为44.9时返回44.90。

有人知道为什么会这样吗?

2 个答案:

答案 0 :(得分:4)

我不知道MS Server是如何工作的,但是根据ANSI SQL规范,列总是有一个特定的数据类型,在这种情况下是十进制(20,2),即可以存储的最小数据类型所有案例的结果类型都不同。

答案 1 :(得分:4)

正如jarlh非常正确地指出case语句将其转换为可能的最小数据类型以保存所有结果类型。 (参见MSDN documentation,特别是返回类型部分)

从我的观点来看,这只是一个显示问题。当44.9变量设置为1时,您希望显示44.90而不是@decimal(请注意尾随零)。

执行此操作的一种方法是向varchar添加其他强制转换。它不漂亮,不是我建议做的事情,但如果你坚持在SQL Server中做格式化和UI类型的事情,那么你能做什么?

DECLARE @Test TABLE(
    Points INT
    ,PointsOf INT
)
INSERT INTO @Test
VALUES (3,12),(2,12),(3,12),(11,12),(12,12),(5,12),(0,12)

DECLARE @Decimal TINYINT = 1


SELECT  
    CASE @Decimal
        WHEN 0 THEN cast(Cast(CAST(SUM(Points) AS DECIMAL(18,0)) / NULLIF(SUM(PointsOf), 0) * 100 as decimal(18,0)) as varchar(10))
        WHEN 1 THEN cast(Cast(CAST(SUM(Points) AS DECIMAL(18,1)) / NULLIF(SUM(PointsOf), 0) * 100 as decimal(18,1))as varchar(10))
        WHEN 2 THEN cast(Cast(CAST(SUM(Points) AS DECIMAL(18,2)) / NULLIF(SUM(PointsOf), 0) * 100 as decimal(18,2))as varchar(10))
    END  AS Score
FROM @Test