我认为最好以简单的例子的形式提出。下面的SQL块会导致“DB-Library错误: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
工作得很好?
答案 0 :(得分:4)
上次我尝试使用Sybase(很多年前)时遇到了同样的问题。来自SQL Server的思维模式,我没有意识到Sybase会尝试强制小数 - 这在数学上是应该做的。 :)
发生算术溢出错误 新类型的小数点太少了 适合结果的地方。
进一步向下:
在隐式转换为数字期间 或十进制类型,规模损失 生成比例错误。使用 arithabort numeric_truncation选项 确定这种错误有多严重 被认为。默认设置, arithabort numeric_truncation on, 中止导致该语句的语句 错误,但继续处理其他 交易中的陈述或 批量。如果你设置arithabort numeric_truncation off,自适应 服务器截断查询结果和 继续处理。
因此假设您的方案中可以接受精度损失,您可能需要在事务开始时使用以下内容:
SET ARITHABORT NUMERIC_TRUNCATION OFF
然后在交易结束时:
SET ARITHABORT NUMERIC_TRUNCATION ON
这就是多年前为我解决的问题......
答案 1 :(得分:1)
这只是猜测,但可能是因为DBMS没有查看变量的动态值而只考虑潜在的值?因此,六位十进制数字除以六位十进制数字可能会产生十二进制数字;在字面分区中,DBMS知道没有溢出。但是仍然不确定为什么DBMS会关心 - 它不应该返回两个六位小数除以18位小数的结果吗?
答案 2 :(得分:1)
因为你已经在第一个例子中声明了变量,所以结果应该是相同的声明(即数字(18,6)),但它不是。
我必须说第一个在SQL2005中工作(返回1.000000 [相同的声明类型])而第二个返回(1.00000000000000000000000 [一个不同的声明])。
答案 3 :(得分:0)
没有直接关联,但可能会使用Sybase ASE(12.5.0.3)在算术溢出错误中节省一些时间。
我在临时表中设置了一些默认值,我打算稍后更新,并偶然发现算术溢出错误。
declare @a numeric(6,3)
select 0.000 as thenumber into #test --indirect declare
select @a = ( select thenumber + 100 from #test )
update #test set thenumber = @a
select * from #test
显示错误:
Arithmetic overflow during implicit conversion of NUMERIC value '100.000' to a NUMERIC field .
我脑子里应该工作,但不是因为'thenumber'列没有声明(或间接声明为十进制(4,3))。所以你必须使用你想要的格式间接地声明临时表列的比例和精度,就像我的情况是000.000。
select 000.000 as thenumber into #test --this solved it
希望能节省一些时间:)