SQL 服务器奇怪的 ROUND() 行为

SQL Server strange ROUND() behaviour

我有大量 table 的产品行...我只需要它的一小部分数据,更具体地说是产品的价格(正常价格 - 我必须在两个字段之间进行选择从某种意义上说,如果存在一个,我会选择它,否则我会选择另一个;以及销售价格——对于许多产品,销售价格存储为带三位小数的浮点数,因为它是按正常价格的百分比计算的)。所以我设计了适当的查询来实现我想要的,并注意到 ROUND() 函数的一个非常奇怪的行为。

在某些情况下,当小数点后第三位数字为 5(即 .165)时,它会被截断为 .16,而在其他情况下,它会四舍五入为 .17,对于小数点后第三位为 5 的任何其他数字都会发生这种情况当然还有地方!这怎么可能?这是查询:

SELECT CODE, FWHSPRICE, RTLPRICE, CASE WHEN ISNULL(FWHSPRICE, 0) = 0 THEN RTLPRICE ELSE FWHSPRICE END AS REGULAR, ROUND(FLDFLOAT3, 2) AS SALE
FROM MATERIAL
WHERE COMID = 12
AND FLTID1 = 1

这里是两个记录集比较的截图,左边查询中没有 ROUND(),右边查询中有 ROUND()

PS:如果您想让我导出数据进行复制,能否请您向我解释一下如何为您创建合适的 INSERT 语句?整个 table 有很多字段和行,我不知道如何设置 SSMS 来做到这一点。我来自 MySQL,所以 SQL 服务器的这个“领域”对我来说太陌生了...提前谢谢你。

是的,您正在混合两种具有自己的古怪行为(恕我直言)的事物。老实说,除非我需要 float 的特定属性,否则我不会使用 float,但是如果你坚持使用这种数据类型......

我会先从 float 转换为 decimal 并多一个小数位(甚至可能是 2 位),然后使用另一个转换来舍入而不是舍入本身。例如:

DECLARE @x TABLE(x float);

INSERT @x(x) VALUES(0.615),(0.165),(0.415),(0.414);

SELECT 
  x, 
  bad    = ROUND(x, 2), 
  better = CONVERT(decimal(10,2), CONVERT(decimal(10,3), x))
FROM @x;

结果:

x bad better
0.615 0.61 0.62
0.165 0.17 0.17
0.415 0.41 0.42
0.414 0.41 0.41

如果您有像 0.4149 这样的值,您可以看到额外的小数位将如何防止四舍五入(除非这是您想要的行为):

DECLARE @f float = 0.4149;

SELECT source     = @f,
       round_up   = CONVERT(decimal(10,2), CONVERT(decimal(10,3), @f)),
       round_down = CONVERT(decimal(10,2), CONVERT(decimal(10,4), @f));

结果:

source round_up round_down
0.4149 0.42 0.41