【问题标题】:SQL Server Rounding Issue Looking for ExplanationSQL Server 舍入问题寻找解释
【发布时间】:2010-01-12 13:48:53
【问题描述】:

我已经解决了这个问题,但我只是想知道为什么会这样。我有一个要从中选择的临时表,并希望显示一个名称、与该名称匹配的记录数以及该名称在总记录中的百分比。这是我最初的方式:

SELECT name, number,  
CASE WHEN number = 0 THEN 0 ELSE
convert(Numeric(10,2), number / CONVERT(decimal(5,2),SUM(number)) * 100)
END as "Percentage of Total" 
FROM #names 
group by name, number

我收到的结果是:

name                      number      Percentage of Total
------------------------- ----------- ---------------------------------------
Test 1                      0           0.00
Test 2                     22          100.00
Test 3                     28          100.00

当我把查询改成这个时,结果是正确的:

    declare @total decimal(5,2)

    select @total = SUM(number) FROM #names

    SELECT name, number, convert(Numeric(10,2), number/ @total * 100) as "Percentage of Total"  
    FROM #names
    group by name, number

正确结果:

name                      number      Percentage of Total
------------------------- ----------- ---------------------------------------
Test 1                     22          44.00
Test 2                      0           0.00
Test 3                     28          56.00

有人可以解释发生了什么,我想更好地理解这一点。谢谢!

乔恩

【问题讨论】:

    标签: sql sql-server stored-procedures rounding


    【解决方案1】:

    您首先按编号查询组。

    由于您没有重复的数字,number / SUM(number) 等同于 1 / COUNT(除非数字是 0)。

    您的第二个查询不按数字分组,它计算总和。

    改用这个:

    SELECT  name, number * 100.0 / SUM(number) OVER ()
    FROM    #names
    

    当与OVER 子句一起使用时,SUM 成为分析函数而不是聚合函数。

    它不会将多条记录压缩为一条:而是将总值与每条记录一起返回:

    -- This is an aggregate function. It shrinks all records into one record and returns the total sum
    
    WITH    q (name, number) AS
            (
            SELECT  'test1', 0
            UNION ALL
            SELECT  'test2', 22
            UNION ALL
            SELECT  'test3', 28
            )
    SELECT  SUM(number)
    FROM    q
    
    --
    50
    

    -- This is an analytical function. It calcuates the total sum as well but does not shrink the records.
    
    WITH    q (name, number) AS
            (
            SELECT  'test1', 0
            UNION ALL
            SELECT  'test2', 22
            UNION ALL
            SELECT  'test3', 28
            )
    SELECT  SUM(number) OVER ()
    FROM    q
    
    --
    50
    50
    50
    

    【讨论】:

    • 哇感谢您的快速响应和出色的回答!你能解释一下 OVER () 在这个查询中做了什么吗?它工作得很好,我只是想了解发生了什么。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-31
    相关资源
    最近更新 更多