在SQL Server 2008中舍入时出现奇怪的行为

时间:2013-11-21 13:49:42

标签: sql sql-server casting rounding

在某些时候,我有一个数字(28,10),我把它投入(我知道它很糟糕但是由于遗产原因我必须返回)同时我还要设置符号(乘以+ 1 / -1)。

在第一次尝试时,我投了+/- 1来匹配数字类型。

对于值 133.3481497944 ,我们遇到了一个奇怪的行为(我已经简化了实际代码,以便只保留演示问题所需的元素)

SELECT CAST(CAST(133.3481497944 AS numeric(28,10))*cast(1 AS numeric(28,10)) AS money)
  

133.3482

未正确舍入...

删除演员解决问题

SELECT CAST(CAST(133.3481497944 AS numeric(28,10)) * 1 AS money)
  

133.3481

有人知道SQL中发生了什么吗?如何乘以1和强制转换(1 AS数字(28,10))会影响舍入的结果?

3 个答案:

答案 0 :(得分:3)

当乘以数字时,SQL使用以下规则来确定输出的精度和比例:

p = p1 + p2 + 1
s = s1 + s2

这是有意义的 - 你不希望1.5 * 2.5被截断为小数点后的一位数。你也不希望101 * 201被限制在3位精度,给你20300而不是20301.

在您的情况下,这将导致精度为57且比例为20,这是不可能的 - 最大精度和比例为38。

如果结果类型太大,则牺牲十进制数字以保留结果的整数(最重要)部分。

来自SQL Programmability & API Development Team Blog

  

在SQL Server 2005 RTM(以及之前的版本)中,我们决定在乘法和除法中保留最小6的范围。

所以你的回答了解 big 精确你需要乘数的方式。为了保留十进制精度的10位数。如果乘数需要大于9的比例,则可能会截断十进制数字。如果你使用较小的精度和比例,你应该没问题:

SELECT CAST(CAST(133.3481497944 AS numeric(28,10))*cast(1 AS numeric(9,7)) AS money)

收益133.3481

答案 1 :(得分:0)

我在这里看不到任何ROUND。我只看到铸造。当你CAST时,不要认为它会变圆。从历史上看,当我们强制转换环境时(不管是SQL服务器)还是行为不如我们所期望的那样 - 特别是当我们谈论FLOAT时。

答案 2 :(得分:0)

SELECT 
CAST(CAST(133.3481497944 AS numeric(28,10))*cast(1 AS numeric(28,10)) AS money) --Your original,
CAST(1 AS numeric(28,10)) --Just the 1 casted,
CAST(133.3481497944 AS numeric(28,10)) --Your expected calculation,
CAST(133.3481497944 AS numeric(28,10))*cast(1 AS numeric(28,10)) -- The actual calculation

SELECT
CAST(133.3481497944 AS numeric(28,10))*cast(1.5 AS numeric(28,10)),
CAST(133.3481497944 AS numeric(28,10))*1.5,
CAST((133.3481497944*1) AS money),
133.3481497944*1

返回

133.3482    
1.0000000000    
133.3481497944  
133.348150


200.022225  
200.02222469160


133.3481    
133.3481497944

正如上面所提到的,确实没有任何真正的舍入,但是在演员阵容期间失去了精确度。至于为什么,我不知道。最有可能在计算(乘法)期间使用数值(28,10)时,它会削减一些精度。

我添加了第二行,以表明您可能不需要数字投射。