回答

收藏

SQL Server:十进制精度/小数位数产生奇怪的结果

技术问答 技术问答 201 人阅读 | 0 人回复 | 2023-09-12

我正在处理一些项目SQL,但我注意到了SQL Server一些看似奇怪的行为,即用小数除法得到的答案是什么。* t' ]# N; n* R+ k" f0 N
以下是我所看到的行为的一些+ E8 V- u+ u% P* ~+ p1 w: c
DECLARE @Ratio Decimal(38,16)SET @Ratio = CAST(210 as Decimal(38,16))/CAST(222 as Decimal(38,16));select @Ratio -- Results in 0.9459450000000000DECLARE @Ratio Decimal(38,16)SET @Ratio = CAST(210 as Decimal)/CAST(222 as Decimal);select @Ratio -- Results in 0.9459459459459459对于上述代码,(似乎)不准确的查询答案给出了更准确的值作为答案。当我同时设置被除数和除数时Decimal(38,16),我得到一个小数位数为6的数字(转换为a会Decimal(38、16)导致0填充小数位数)。3 N6 I/ p# c: m8 R7 l3 ?% n6 C; g! d
当我只将除数和除数转换为默认的十进制,而不手动设置精度或小数位数时,我得到的小数位数都是16位。5 s- l! o* ^* O' S
出于好奇,我开始用以下查询来做更多的实验:1 ~! ^9 W4 Y5 X* I( F
select CAST(210 as Decimal(38,16))/CAST(222 as Decimal(38,16)) --0.945945select CAST(210 as Decimal(28,16))/CAST(222 as Decimal(28,16)) --0.9459459459select CAST(210 as Decimal(29,16))/CAST(222 as Decimal(29,16)) --0.945945945正如你所看到的,随着我精度的提高,答案的规模似乎降低了。我看不到结果的规模与除数和除数的规模或精度之间的相关性。. e+ b( c% Q0 p$ W; ~2 ]+ b" p' v, o
我发现了其他一些问题,它们指向msdn该位置指出,通过对除数和除数的精度和小数位数进行一组计算,可以确定运算小数时获得的精度和小数位数,并且:
/ F+ h1 P7 G" |# b3 U( l结果精度和小数位的绝对最大值为38。当结果精度大于38时,相应的小数位会降低,以防止结果的整数被切断。
$ j  T- y+ T: f( Y; s+ }" u/ {/ c
因此,我试图通过这些方程式来确定aDecimal(38,16)分解成另一个Decimal结果,根据我的发现,我仍然应该得到比我更准确的数字。3 I3 ~2 u3 n4 M2 z# o
所以我做错了数学,或者这是我缺少的其他事情。非常感谢您的意见。
% s! q- n, T! n4 n. t, F提前致谢…( l) F1 s! N6 `
                                                                5 f! C$ S' z$ d" T
    解决方案:                                                               
% ~) |% n1 R8 w1 d( t  B4 R& g                                                                文档不完整,关于价值的奥秘以及何时应用函数,但这是基于文档的调查结果表。``max
8 N1 {! y! I7 I: D4 i例如,除法公式为:
: ?% @- ?/ M, D' I# }. s结果精度= p1-s1   s2   max(6,s1   p2   1)    ,结果标准= max(6,s1   p2   1)
  A) Z/ Q- F5 B. A而且,就像你自己突出的那样,我们会加脚注:2 r( u" a0 z' D7 ~# B( H9 b4 J0 I
结果精度和小数位的绝对最大值为38。当结果精度大于38时,相应的小数位会降低,以防止结果的整数被切断。
# h8 p+ F. D* f% W因此,这是我在电子表格中生成的:
8 h4 \& Z. W0 M9 C( d' hp1 s1 p2 s2 prInit srInit prOver prAdjusted srAdjusted38 16 38 16 93   55555  5555                  38 628 16 16 28 16 16 16 33    35     35      35    35                                                       55555555555555555555555     3838 38 3838 3838 165555  555555 555555555555555555555555555555555555555                                                                                                                                                                                                              5555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555                                          所以,我在用pr和sr指示结果的精度和小数位数。prInit和srInit公式完全来自文档forumlas。在所有三种情况下,结果的精度都远远大于38,因此脚注适用。prOver只是max(0,prInit- 38)-若脚注适用,必须调整多少精度。prAdjusted就是prInit -prOver。在这三种情况下,我们都可以看到结果的最终精度是38。8 n$ F1 E% |1 ~
如果我申请 相同的* U/ t( J* [% l( l
调整因子,去鳞,然后我会得到0、10和9的结果。但我们可以看到,你对这个(38、16)案例的结果是6级。所以,我觉得是max(6,...文档部分实际适用的地方。所以我的最终公式srAdjusted是max(6,srInit-prOver),现在我的终点Adjusted值似乎与你的结果相匹配。  `* ~3 A+ O9 [4 K& V
当然,如果我们参考文档decimal,我们可以看到 默认' N' Q* t( h: ~& o
精度和小数位数(如果你没有指定)是(18,0),所以这是没有指定精度和小数位数的行:' a8 o; G# g5 U" e
p1 s1 p2 s2 prInit srInit prOver prAdjusted srAdjusted180 180 180 37    1919        37        19
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则