SQL 数字数据类型截断值?

标签 sql sql-server sql-server-2005 decimal numerical-methods

我真的希望那里的一些 SQL 大师可以帮助解决这个问题(如果之前有人回答过,我深表歉意。我确实尝试找到了类似的帖子,但无济于事):

declare @theanswer numeric(38,16)

select @theanswer = 0.01 / 0.0074464347
select @theanswer

以上结果为1.3429245542165000

但是下面的(对我来说看起来一样)

declare @val1 numeric(38,16);
declare @val2 numeric(38,16);

set @val1 = 0.01;
set @val2 = 0.0074464347;

select @val1/@val2

结果为 1.342924 并截断它?

有什么想法吗?

最佳答案

要获得结果的真实精度和比例 (@val1/@val2),我将执行此 T-SQL 脚本

DECLARE @val1 NUMERIC(38,16);
DECLARE @val2 NUMERIC(38,16);

SET @val1 = 0.01;
SET @val2 = 0.0074464347;

SELECT @val1/@val2
        ,SQL_VARIANT_PROPERTY(@val1/@val2, 'BaseType')  [BaseType]
        ,SQL_VARIANT_PROPERTY(@val1/@val2, 'Precision') [Precision]
        ,SQL_VARIANT_PROPERTY(@val1/@val2, 'Scale')     [Scale]

结果将是:

(No column name)    BaseType    Precision   Scale
1.342924            numeric         38          6

因此,结果精度为 38,结果小数位数为 6。 MSDN 有一些关于算术运算的精度和小数位数的细节。这些信息可以在这里找到:Precision, Scale, and Length (Transact-SQL) :

Operation = e1 / e2
Result precision = p1 - s1 + s2 + max(6, s1 + p2 + 1)
Result scale * = max(6, s1 + p2 + 1)

使用这些公式,我们可以编写下一个 T-SQL 脚本以获得理论精度和结果的比例 (@val1/@val2):

SELECT   @p1 = 38   --or CONVERT(INT, SQL_VARIANT_PROPERTY(@val1, 'Precision'))
        ,@s1 = 16   --or CONVERT(INT, SQL_VARIANT_PROPERTY(@val1, 'Scale'))
        ,@p2 = 38   --or CONVERT(INT, SQL_VARIANT_PROPERTY(@val2, 'Precision'))
        ,@s2 = 16   --or CONVERT(INT, SQL_VARIANT_PROPERTY(@val2, 'Scale'));

--SELECT    @p1 [@p1], @s1 [@s1], @p2 [@p2], @s2 [@s2];

SELECT  @p_result = @p1 - @s1 + @s2 +   CASE 
                                            WHEN 6 >= @s1 + @p2 + 1 THEN 6 
                                            WHEN 6 < @s1 + @p2 + 1 THEN @s1 + @p2 + 1 
                                        END
        ,@s_result =    CASE 
                            WHEN 6 >= @s1 + @p2 + 1 THEN 6 
                            WHEN 6 < @s1 + @p2 + 1 THEN @s1 + @p2 + 1 
                        END;

SELECT  @p_result [@p_result], @s_result [@s_result];

结果是:

@p_result   @s_result
93          55

因此,对于这个算术运算 (@val1/@val2),理论上 的精度和小数位数是 9355 但实际精度和小数位数是 386。 实际精度为 38,因为结果精度和小数位数的绝对最大值为 38

关于real result scale (6) MSDN并不清楚:“当结果精度大于38时,相应的scale被减小以防止结果的整数部分被截断”

为了查看“相应比例减小”的情况,我使用具有相同比例的 NUMERIC 值执行了上述测试(脚本 1 用于实际精度和比例,脚本 2 用于理论精度和比例)( 16) 但规模不同(从 16 到 38)。这些测试的结果是:

/*
Result prec. Result scale   (T=theoretical value, R=real value)
 T-R         T-R            --@val1 and @val2 data type
49-38       33-22           --NUMERIC(16, 16)
51-38       34-21           --NUMERIC(17, 16)
53-38       35-20           --NUMERIC(18, 16)
55-38       36-19           --NUMERIC(19, 16)
...
61-38       39-16           --NUMERIC(22, 16) -- <-- data type for [real] result scale 16
...                         
77-38       47-8            --NUMERIC(30, 16)
79-38       48-7            --NUMERIC(31, 16)
81-38       49-6            --NUMERIC(32, 16)
83-38       50-6            --NUMERIC(33, 16)
85-38       51-6            --NUMERIC(34, 16)
...
93-38       55-6            --NUMERIC(38, 16)
*/

检查这些结果:

1.我看到真实结果等级的等差级数:从 22 到 6,步长 -1。

2.此外,如果 @val1 和 @val2 的比例是常数 (NUMERIC(...,16)),则 @val1 和 @val2 精度之间存在负相关(从 16到 32)和 [真实] 结果等级(从 16 到 6)。

3.如果@val1 和@val2 精度为 32 或更高 (NUMERIC(32->38,16)),则 [real] 结果比例始终为 6 => 这就是你的情况.

4.如果需要更大的 [真实] 结果比例(超过 6),您需要为 @val1 使用较低的精度 和@val2:NUMERIC(22, 16):

SELECT          
         CONVERT(NUMERIC(22,16),@val1) / CONVERT(NUMERIC(22,16),@val2) [CONVERT(NUMERIC(22,16)]
        ,SQL_VARIANT_PROPERTY( CONVERT(NUMERIC(22,16),@val1) / CONVERT(NUMERIC(22,16),@val2) , 'BaseType')  [BaseType]
        ,SQL_VARIANT_PROPERTY( CONVERT(NUMERIC(22,16),@val1) / CONVERT(NUMERIC(22,16),@val2) , 'Precision') [Precision]
        ,SQL_VARIANT_PROPERTY( CONVERT(NUMERIC(22,16),@val1) / CONVERT(NUMERIC(22,16),@val2) , 'Scale')     [Scale] 

CONVERT(NUMERIC(22,16) BaseType Precision Scale
---------------------- -------- --------- -----
1.3429245542165299     numeric  38        16

关于SQL 数字数据类型截断值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7913328/

相关文章:

sql - 多次连接后删除重复项

javascript - 什么是服务器日志以及如何生成它们?

SQL 服务器 : Easiest way to copy users from dev -> prod

sql - 如何根据 SQL Server 2005 中的条件返回值集?

sql - 查询大量记录以找到 1 个字段不同但另外 2 个字段匹配的模式(即使颠倒)

c# - SQL 添加数据的权限以及如何验证?

sql - 将图像数据导出到平面文件

sql - 如何在更改列字符串之前从 SQL 表中获取所有行?

php - 使用 PHP 连接到 Microsoft SQL 服务器

sql - 如何取消透视三种类型的值(包括列标题)