【问题标题】:Why does SQL Server override my scale value when I am casting from VARCHAR(MAX) to Numeric(P,S)?当我从 VARCHAR(MAX) 转换为 Numeric(P,S) 时,为什么 SQL Server 会覆盖我的比例值?
【发布时间】:2022-01-26 19:40:51
【问题描述】:

我试图理解为什么当我将值从 VARCHAR(MAX) 转换为 NUMERIC(P,S) 时,SQL Server 会修改我的比例值。

示例如下:

--declare @val1 as numeric (18,6)
--declare @val2 as numeric (18,6)

DECLARE @val1 AS VARCHAR(MAX)
DECLARE @val2 AS VARCHAR(MAX)

SET @val1 = '2383.4912500000'
SET @val2 = '2383.4912000000'

DROP TABLE IF EXISTS TMP

SELECT
    V1 = @VAL1, 
    VC1 = CAST(@VAL1 AS NUMERIC(30, 20)),
    valDiff = ABS(CAST(CAST(@VAL2 AS NUMERIC(18, 6)) - CAST(@VAL1 AS NUMERIC(18, 6)) AS NUMERIC(30, 20)) / @VAL1) 
INTO  
    TMP

SELECT * FROM TMP

-- when variable is VARCHAR(MAX), valDiff == 0.00000002 which is correct, but rounded.

-- when the variable is NUMERIC(18, 6), valDiff == 0.0000000209776310275945 which is correct and not rounded

【问题讨论】:

  • 您考虑过...不在varchar(max) 中存储数字吗?
  • 是的。这不是我的代码库。拥有此代码的团队不太了解他们的 SQL 能力。我最感兴趣的是了解 SQL Server 为何这样做。
  • valDiff的数据类型是decimal(38,8).. 0.00000002 :: 8个小数点
  • @lptr 我知道 SQL 创建的数据类型。问题是为什么它设置为 38,8?我将变量转换为 30,20?
  • @mdiprima .. 是的,分母 @val1[varchar] 隐式转换为分子的数字数据类型。第一个是 (30,20)/(30,20) — > (38,8) 第二个 (18,6)/(18,6)—>(38,20)

标签: sql sql-server sqldatatypes


【解决方案1】:

当您从精度非常高的小数开始时,算术运算的结果可能会缩小其比例以保留更多有效数字。如果值没有小数点左侧有 30 个非零数字,则无关紧要。转换基于声明的精度和比例:

Precision and Scale

在这里,您的 varchar 正在以过高的精度隐式转换为小数。

由于需要小心地将中间结果转换为小数,因此使用 float 执行所有计算通常更容易,它在所有尺度上保持约 15 位有效数字的精度,并且仅将最终结果转换为 decimal用于存储。例如

declare @val1 as float ='2383.4912500000'
declare @val2 as float ='2383.4912000000'

select cast( abs(@VAL2 - @VAL1) / @VAL1 as numeric(30,20) )

【讨论】:

  • 是的,我现在看到了。我早些时候试图理解矩阵,但我没有看到下面用于乘法和除法的额外条件。在我的工作中正确包含这些条件之后,我现在能够看到我工作中的价值。感谢您的分享,感谢您的浮动推荐!
猜你喜欢
  • 2019-09-07
  • 1970-01-01
  • 2021-04-26
  • 1970-01-01
  • 1970-01-01
  • 2012-05-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多