sql - SQL Server 似乎舍入不正确
问题描述
我有一个存储课程结果的表。一门课程可能有多个考试,每个考试都有自己的权重。
在这个例子中,我有一个学生的 2 个考试分数,然后加权以给出课程分数。标记和权重都存储在 FLOAT 列中。
这是我提取考试成绩的代码:
WITH RawData AS
(
SELECT
lngRelatedScoreID AS [ID],
cc.strName AS Exam,
cc.dblWeighting,
sci.dblModeratedComponentScorePercent AS Mark
FROM
tblStudentComponentInformation sci
INNER JOIN
tblCourseComponents cc ON sci.lngExamID = cc.lngExamID
WHERE
sci.lngRelatedScoreID IN (73652)
)
SELECT * FROM RawData
结果显示如下:
ID | 考试 | dbl加权 | 标记 |
---|---|---|---|
73652 | 飞行动力学和控制考试 | 0.75 | 0.905 |
73652 | 飞行动力学和控制课程 | 0.25 | 0.92 |
我现在将这两行合并,将权重乘以标记:
WITH RawData AS
(
SELECT
lngRelatedScoreID AS ID,
cc.strName AS Exam,
cc.dblWeighting,
sci.dblModeratedComponentScorePercent AS Mark
FROM
tblStudentComponentInformation sci
INNER JOIN
tblCourseComponents cc ON sci.lngExamID = cc.lngExamID
WHERE
sci.lngRelatedScoreID IN (73652)
)
SELECT
[ID],
SUM(Mark * dblWeighting) AS TotalWeightedMark
FROM
RawData
GROUP BY
[ID]
它返回以下 - 正如预期的那样:
ID | 总加权标记 |
---|---|
73652 | 0.90875 |
但是,我希望结果到小数点后 4 位,所以当我将标记乘以四舍五入并对结果求和时,我在ROUND
函数中添加:
WITH RawData AS
(
SELECT
lngRelatedScoreID AS ID,
cc.strName AS Exam,
cc.dblWeighting,
sci.dblModeratedComponentScorePercent AS Mark
FROM
tblStudentComponentInformation sci
INNER JOIN
tblCourseComponents cc ON sci.lngExamID = cc.lngExamID
WHERE
sci.lngRelatedScoreID IN (73652)
)
SELECT
[ID],
ROUND(SUM(Mark * dblWeighting), 4) AS TotalWeightedMark
FROM
RawData
GROUP BY
[ID]
这就是我得到的回报:
ID | 总加权标记 |
---|---|
73652 | 0.9087 |
我的问题是为什么这似乎是截断而不是四舍五入,因为我没有指定除ROUND
函数最终参数的默认值之外的任何内容。
我想知道这是否是因为使用FLOAT
而不是DECIMAL
用于列,但在这种情况下,计算中不需要任何舍入,除了我指定从 5 位四舍五入到 4 的计算。
任何人都可以建议吗?
如果相关,我使用的是 SQL Server 2017。
谢谢。
解决方案
正如评论中提到的,“问题”是数据类型,而不是表达式。
如果我们看下面的例子:
SELECT [ID],
SUM(FloatWeighting*FloatMark) AS Float,
SUM(Decimalweighting*DecimalMark) AS Decimal,
CONVERT(decimal(18,12),SUM(FloatWeighting*FloatMark)) AS ConvertedFloat,
ROUND(SUM(FloatWeighting*FloatMark),4) AS RoundedFloat,
ROUND(SUM(Decimalweighting*DecimalMark),4) AS RoundedDecimal
FROM (VALUES(73652,'Flight Dynamics and Control Exam ',CONVERT(float,0.75),CONVERT(decimal(3,2),0.75),CONVERT(float,0.905),CONVERT(decimal(4,3),0.905)),
(73652,'Flight Dynamics and Control Coursework',CONVERT(float,0.25),CONVERT(decimal(3,2),0.25),CONVERT(float,0.92),CONVERT(decimal(4,3),0.92)))V(ID,Exam,FloatWeighting,DecimalWeighting,FloatMark,DecimalMark)
GROUP BY ID;
如果你运行它,你会得到以下结果:
ID Float Decimal ConvertedFloat RoundedFloat RoundedDecimal
----- ------- ------- -------------- ------------ --------------
73652 0.90875 0.90875 0.908750000000 0.9088 0.90880
请注意,四舍五入的decimal
值提供了您期望的值,但四舍五入的值float
没有。这是因为,正如评论中所讨论的,浮点值不是以 10 为底的值,而是以 2 为底的值。结果,该float
值实际上0.90875
不是,而是。请注意,该值实际上(仅)小于。 0.90875
0.908749999999999946709294817992486059665679931640625
0.90875
因此,当您应用该函数时,将ROUND
使用上述值,并且当您ROUND
将该值保留到小数点后 4 位时,这0.9087
就是正确的答案。
因此,这里真正的解决方案是修复您的设计和ALTER
表格以使列成为decimal
. 例如,这可能是:
ALTER TABLE dbo.tblCourseComponents ALTER COLUMN Mark decimal(4,3);
请注意,您需要为实际值使用适当的比例和精度。
如果您不能更改数据类型,或者至少现在不能,那么您可以decimal
在算术之前将值显式转换为第一个。例如:
ROUND(SUM(CONVERT(decimal(3,2),Weighting)*CONVERT(decimal(4,3),Mark)),4)
同样,确保您为数据使用适当的精度和比例。
推荐阅读
- java - Srping/休眠:spring.entity.Downloads 不能转换为 java.lang.Integer
- python - 如何编写程序将数组中的元素与下一个元素相乘并将输出作为数组给出
- keras - 我应该如何使用 coreML convert 为模型输出提供标签名称
- excel - 循环创建大量数据透视表
- python - Heroku Flask Socketio 无法导入名称“命名空间”
- java - Jackson 将 YAML 文件反序列化为 Map(没有自定义反序列化器)
- sql - 使用 SQL 有条件地对连续行求和
- python - 用破折号(-)python划分字符串
- c# - 从返回类型 DataSet 获取输出并将其显示在 Gridview 中
- sql - 如何在具有相同列的两个表中找到不同的行?