避免TSQL数据转换错误
时间:2020-03-06 15:03:34 来源:igfitidea点击:
我认为最好以一个简单的例子的形式提出。下面的SQL块会导致" DB库错误:20049严重性:4消息:数据转换导致溢出"消息,但是怎么回事呢?
declare @a numeric(18,6), @b numeric(18,6), @c numeric(18,6) select @a = 1.000000, @b = 1.000000, @c = 1.000000 select @a/(@b/@c) go
这与以下内容有何不同?
select 1.000000/(1.000000/1.000000) go
哪个工作正常?
解决方案
这仅仅是推测,但是可能是DBMS不在查看变量的动态值,而是仅查看潜在值?因此,将六进制数字除以六进制数字可能会导致十二进制数字。在字面上的划分中,DBMS知道没有溢出。仍然不确定为什么DBMS会关心-它是否不应该返回两个六进制十进制除法的结果,直到一个18进制十进制数呢?
因为我们已经在第一个示例中声明了变量,所以结果应该是相同的声明(即数值(18,6)),但事实并非如此。
我不得不说,第一个在SQL2005中工作(返回1.000000 [相同的声明类型]),而第二个返回了(1.00000000000000000000000 [完全不同的声明])。
我上次尝试使用Sybase时遇到了相同的问题(很多年前)。从SQL Server的心态出发,我没有意识到Sybase会试图强制将小数点强制掉-从数学上讲,这是它应该做的。 :)
从Sybase手册中:
Arithmetic overflow errors occur when the new type has too few decimal places to accommodate the results.
再往下走:
During implicit conversions to numeric or decimal types, loss of scale generates a scale error. Use the arithabort numeric_truncation option to determine how serious such an error is considered. The default setting, arithabort numeric_truncation on, aborts the statement that causes the error but continues to process other statements in the transaction or batch. If you set arithabort numeric_truncation off, Adaptive Server truncates the query results and continues processing.
因此,假设在情况下精度损失是可以接受的,那么我们可能希望在交易开始时进行以下操作:
SET ARITHABORT NUMERIC_TRUNCATION OFF
然后在交易结束时:
SET ARITHABORT NUMERIC_TRUNCATION ON
这就是很多年前为我解决的问题...