T-SQL无法正确执行聚合的算术计算

时间:2018-08-20 17:01:03

标签: sql-server tsql aggregates

我有一个表变量,该变量存储按员工分组的两个单独的子任务的平均时间。我需要添加一条记录,存储整个公司针对这两项任务计算出的加权平均值。

我添加了一个列,该列存储每个员工执行每个子任务所需的平均时间,然后将其乘以该员工执行的总任务数。

我通过以下查询用每个员工的记录填充表:

 DECLARE @TotalNumberTasks INT
        ,@CompanyName VARCHAR(50) = 'Company ABC'

SELECT @TotalNumberTasks = COUNT(*) FROM Tbl1 --2436

INSERT INTO @OutputTemp
(
    EmployeeID
    ,EmployeeName 
    ,AverageTimeSubTask1
    ,AverageTimeSubTask2
    ,NumberTasks
    ,SqlComputedSubTask1WeightedNumber
    ,SqlComputedSubTask2WeightedNumber
) 
SELECT TaskPerformedByUserID
        ,TaskPerformedByUserName
        ,AVG(CAST(SubTask1Time AS DECIMAL(6,2)))
        ,AVG(CAST(SubTask2Time  AS DECIMAL(6,2)))
        ,COUNT(*)
        ,AVG(CAST(SubTask1Time AS DECIMAL(6,2))) * COUNT(*)
        ,AVG(CAST(SubTask2Time  AS DECIMAL(6,2))) * COUNT(*)
FROM Tbl1
GROUP BY TaskPerformedByUserID, TaskPerformedByUserName

一旦有了这些信息,我就会使用以下查询添加所需的公司汇总行:

INSERT INTO @OutputTemp
(
    EmployeeID
    ,EmployeeName 
    ,AverageTimeSubTask1
    ,AverageTimeSubTask2 
)
SELECT  NULL
        ,@CompanyName
        ,SUM(CAST(SqlComputedSubTask1WeightedNumber AS DECIMAL(6,2)))/@TotalNumberTasks
        ,SUM(CAST(SqlComputedSubTask2WeightedNumber AS DECIMAL(6,2)))/@TotalNumberTasks
FROM @OutputTemp

我面临的问题是,每位员工获得公司平均值的加权值计算不正确。在下面的示例表结构示例中,我还添加了两列来显示正确的值。

enter image description here

我不知道为什么会这样。我了解到,当每个数字四舍五入时,除法将导致小数点后的信息丢失,但是可以。问题是在某些情况下它不能四舍五入为正确的整数。

此外,计算甚至没有一致地进行。例如,在Employee1的记录上,正在执行相同的精确计算(.06 * 145),它会导致两个单独的值7和8。

我环顾四周,认为问题可能与此post有关,但是当我尝试按照建议将分母转换为浮点型时,我得到了完全相同的结果。

任何帮助都将不胜感激。

编辑:

这是我正在使用的@OutputTemp的初始表变量声明:

DECLARE @OutputTemp TABLE
(
    EmployeeID INT
    ,EmployeeName VARCHAR(75)
    ,AverageTimeSubTask1 DECIMAL(6,2) 
    ,AverageTimeSubTask2 DECIMAL(6,2)
    ,NumberTasks INT
    ,SqlComputedSubTask1WeightedNumber INT
    ,SqlComputedSubTask2WeightedNumber INT
)

这是经过修改的表变量结构,可以解决此问题。

  DECLARE @OutputTemp TABLE
(
    EmployeeID INT
    ,EmployeeName VARCHAR(75)
    ,AverageTimeSubTask1 DECIMAL(10,8) 
    ,AverageTimeSubTask2 DECIMAL(10,8)
    ,NumberTasks INT
    ,SqlComputedSubTask1WeightedNumber INT
    ,SqlComputedSubTask2WeightedNumber INT
)

由于我使用的是AverageTimeSubTask1AverageTimeSubTask2的类型定义,该类型定义将值的范围限制为两位小数,因此我将temp变量中的值误认为是计算,如@WolfgangKais所述。

这是在更改两次平均子任务时间的精度和小数位数后的@OutputTemp结构:

enter image description here

如您所见,计算确实在正确执行。

2 个答案:

答案 0 :(得分:0)

首先,在更深入地进行故障排除之前,我会确保没有空值干扰我的数据集,并且仅处理质量数据:

在INSERT INTO @OutputTemp查询中,在select中添加此条件:WHERE Employee is Null

此外,我会事先使用适当的列类型声明@OutputTemp表,这样我就不必在最后一刻强制转换值。

答案 1 :(得分:0)

1)例如,只有一个结尾为小数(14,4),count返回类型优先级较低的INT,SQL将强制转换为十进制以匹配最高类型。

2)浮点数和实数类型都不是精确类型,因此您永远不会像我在前一点中所建议的那样拥有至少十个小数点后四位的十进制精度。

尝试一下:

SELECT TaskPerformedByUserID
        ,TaskPerformedByUserName
        ,cast(COUNT(*) as decimal(14,4))/(select count(*) from Tbl1) * 100 percent_to_total
FROM Tbl1
GROUP BY TaskPerformedByUserID, TaskPerformedByUserName