【问题标题】:Avoiding TSQL Data-conversion errors避免 SQL 数据转换错误
【发布时间】:2010-09-14 23:51:24
【问题描述】:

我认为最好以简单示例的形式提出这个问题。以下 SQL 块导致 “DB-Library Error:20049 Severity:4 Message:Data-conversion 导致溢出” 消息,但这是怎么回事?

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

哪个好用?

【问题讨论】:

  • 我不知道这是否增加了任何东西,但 select (@a*@b)/@c 在代数上是相同的会发生什么。

标签: tsql sybase data-conversion


【解决方案1】:

我上次尝试使用 Sybase 时遇到了同样的问题(很多年前)。从 SQL Server 的思维方式出发,我没有意识到 Sybase 会尝试强制输出小数 - 从数学上讲,这是它应该做的事情。 :)

来自Sybase manual

算术溢出错误发生在 新类型的小数太少 容纳结果的地方。

再往下:

在隐式转换为数字期间 或小数类型,比例损失 产生比例误差。使用 arithabort numeric_truncation 选项 确定此类错误的严重程度 被认为。默认设置, arithabort numeric_truncation on, 中止导致 错误但继续处理其他 交易中的陈述或 批。如果你设置 arithabort numeric_truncation 关闭,自适应 服务器截断查询结果并 继续处理。

所以假设在您的场景中精度损失是可以接受的,您可能希望在事务开始时执行以下操作:

SET ARITHABORT NUMERIC_TRUNCATION OFF

然后在交易结束时:

SET ARITHABORT NUMERIC_TRUNCATION ON

这就是多年前为我解决的问题......

【讨论】:

    【解决方案2】:

    这只是推测,但是否 DBMS 不查看变量的动态值而只查看潜在值?因此,一个六进制数字除以一个六进制数字可以得到一个十二进制数字;在字面除法中,DBMS 知道没有溢出。不过,仍然不确定 DBMS 为何会关心 - 它不应该将两个 6 位小数除法的结果返回为 18 位小数吗?

    【讨论】:

      【解决方案3】:

      因为您在第一个示例中声明了变量,所以结果应该是相同的声明(即数字 (18,6)),但事实并非如此。

      我不得不说第一个在 SQL2005 中工作(返回 1.000000 [相同的声明类型]),而第二个返回(1.00000000000000000000000 [完全不同的声明])。

      【讨论】:

        【解决方案4】:

        没有直接关系,但可能会在使用 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 .
        

        在我的脑海中应该可以工作,但没有声明“数字”列(或间接声明为十进制(4,3))。因此,您必须以所需格式间接声明具有比例和精度的临时表列,如我的情况是 000.000。

        select 000.000 as thenumber into #test --this solved it
        

        希望这可以节省一些时间:)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-08-13
          • 2013-04-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-03-22
          • 1970-01-01
          相关资源
          最近更新 更多