具有高精度和小数位数的小数创建 'Arithmetic Overflow Error'

Decimal with high precision and scale creating 'Arithmetic Overflow Error'

我使用 BCP 将大量数据导入 SQL 服务器,其中包含所有字符串。为了进一步保持数据库的完整性,我正在更改所有列以获得正确的元数据。

我有一个当前字符串列,它实际上充满了十进制值,需要更改该列以使其成为十进制 (p, s)。

由于数据量大,我写了下面的查询来获取小数点前后字符串的最大长度;添加小数点前后的字符串长度以获得精度。以下查询将显示我到达的结果:

SELECT 
    '('
    +
    CAST(MAX(LEN(LEFT(Measure, LEN(Measure) - LEN(SUBSTRING(Measure, CHARINDEX('.', Measure) , 255))))) 
    + 
    MAX(LEN(SUBSTRING(Measure, CHARINDEX('.', Measure) +1, 255))) AS varchar(5)) 
    + 
    ',' 
    + CAST(MAX(LEN(SUBSTRING(Measure, CHARINDEX('.', Measure) +1, 255))) AS varchar(5))
    +
    ')' AS 'max[p,s]'
FROM
    Result

结果如下:

max[p,s]
--------
(24,19)

当我通过以下说明更改列时:

ALTER TABLE Result
ALTER COLUMN Measure DECIMAL (24,19)

我收到以下错误:

Msg 8115, Level 16, State 8, Line 1 Arithmetic overflow error converting varchar to data type numeric. The statement has been terminated.

(p,s) where p = precision and s=scale;我的印象是我的最大精度 (p) 可以达到 38。为什么会出现此错误?有什么建议么?重要的是我不能失去任何精度。

您可以尝试使用以下方法查找坏行:

select Measure from Result 
where TRY_CONVERT(DECIMAL(24,19),Measure)  
is Null And Measure is Not Null;

来自 MSDN decimal and numeric (Transact-SQL)

p (precision) The maximum total number of decimal digits that will be stored, both to the left and to the right of the decimal point. The precision must be a value from 1 through the maximum precision of 38. The default precision is 18.

要获得精度,请使用:

SELECT  MAX(LEN(Measure)) AS max_precision_needed 
FROM    Result

上面的查询没有减去小数点,因为字符串可能包含一个根本没有小数点的整数。它为您提供了可能的最大需求。

示例: 数字 123.00 需要具有以下精度的字段;十进制(5,2)

在下面的示例中,计算出所需的精度后,就可以进行转换了。

   DECLARE @measures TABLE ( measure VARCHAR(50) );

   INSERT   INTO @measures( measure ) VALUES   ( '123' )
   INSERT   INTO @measures( measure ) VALUES   ( '123.00' )
   INSERT   INTO @measures( measure ) VALUES   ( '123.001' )
   INSERT   INTO @measures( measure ) VALUES   ( '.123' )
   INSERT   INTO @measures( measure ) VALUES   ( '0.123' )
   INSERT   INTO @measures( measure ) VALUES   ( '   ' )

   SELECT   '(' + CAST(MAX(LEN(measure)) - 1 AS VARCHAR(5)) + '.' + CAST(MAX(LEN(SUBSTRING(measure, CHARINDEX('.', measure) + 1, 255))) AS VARCHAR(5)) + ')'
   FROM     @measures

   SELECT   ISNULL(CONVERT(DECIMAL(6, 3), CASE WHEN CHARINDEX('.', measure) = 0 THEN measure + '.0' ELSE measure END), 0.0)
   FROM     @measures

在此示例中,转换不应因字符串中的整数或空字符串而失败。