【问题标题】:T-SQL : how to disable overflow checks on integer operations?T-SQL:如何禁用整数运算的溢出检查?
【发布时间】:2018-03-01 21:26:43
【问题描述】:

在 C# 中,我们有 unchecked 来禁用整数运算的溢出检查

int int1;
unchecked
{
    int1 = 2147483647 + 10;
}

整数运算结果将换行为 -2,147,483,639

但在 T-SQL 中我找不到禁用边界检查的方法

DECLARE @INT1 INT
SET @INT1 = 2147483647 + 10

导致错误:

消息 8115,第 16 级,状态 2,第 2 行
将表达式转换为数据类型 int 的算术溢出错误。

【问题讨论】:

  • 我认为TSQL中没有这种东西。
  • 我更新了我的答案,以提供一个更简洁的示例,说明如何从计算中获取 BigInt 结果并将其转换为 Int 而不会以适合在查询或函数中使用的方式溢出。

标签: tsql int overflow integer-overflow integer-arithmetic


【解决方案1】:

我并不认为这一定是个好主意,但您可以将其包装在 try/catch 中。

declare @int int;

begin try
  set @int = 2147483647 + 10
end try
begin catch
  if ERROR_NUMBER() = 8115 
    set @int = 2147483647
  else 
    select
        ERROR_NUMBER() AS ErrorNumber  
       ,ERROR_MESSAGE() AS ErrorMessage;  
end catch 

select @int

结果:

2147483647

【讨论】:

    【解决方案2】:

    根据Microsoft specification,由于 INT 数据类型范围从 -2,147,483,648 到 2,147,483,647,因此无法执行该操作 (2147483647 + 10)。

    相反,您可以使用 BIGINT 数据类型,如下所示:

    DECLARE @number BIGINT;
    SET @number = CAST(2147483647 AS BIGINT) + 10;
    SELECT @number;
    -- Output: 2147483657, as expected
    

    【讨论】:

      【解决方案3】:

      您可以将int 值转换为bigint,执行加法,然后处理溢出,同时使用case 表达式转换回int

      declare @MaxInt as BigInt = Power( Cast( 2 as BigInt ), 31 ) - 1;
      declare @Foo as Int = 2147483647;
      declare @Bar as Int = 10;
      declare @BigSum as BigInt;
      set @BigSum = @Foo + Cast( 10 as BigInt );
      select @MaxInt as MaxInt, @Foo as Foo, @Bar as Bar, @BigSum as BigSum,
        case when @BigSum <= @MaxInt then Cast( @BigSum as Int ) else
          Cast( @BigSum - Power( Cast( 2 as BigInt ), 32 ) as Int ) end as Unsigned;
      

      更新:一个更简洁的示例展示了如何获取 BigInt 结果(来自先前的计算)并将其转换为 Int 而不会溢出:

      declare @Samples as Table ( Value BigInt );
      insert into @Samples ( Value ) values
        -- NB: At least one literal value needs to be cast as a BigInt to get BigInt values.  No, really.
        ( Cast( 0x0 as BigInt ) ), ( 0x1 ), ( 0x7FFFFFFF ), ( 0x80000000 ), ( 0x80000001 ), ( 0xFFFFFFFF ),
        ( -1 ), ( 0x4200000001 ), ( 0x7080000000 ); -- Some BigInt values beyond 32 bits.
      
      select Value, Cast( Value as Binary(8) ) as ValueHex,
        Value & 0xFFFFFFFF as LSB32, Cast( Value & 0xFFFFFFFF as Binary(8) ) as LSB32Hex,
        Cast( case when Value & 0x80000000 = 0 then Value & 0xFFFFFFFF else
          ( Value & 0x7FFFFFFF ) - Cast( 0x80000000 as BigInt ) end as Int ) as IntResult
        from @Samples;
      

      虽然性能可能会受到影响,但可以将转换捆绑到 UDF 中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-01-03
        • 2012-05-17
        • 2016-05-30
        • 1970-01-01
        • 2019-01-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多