在某些时候,我有一个数字(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))会影响舍入的结果?
答案 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)时,它会削减一些精度。
我添加了第二行,以表明您可能不需要数字投射。