【问题标题】:SQL - safely downcast BIGINT to INTSQL - 安全地将 BIGINT 向下转换为 INT
【发布时间】:2011-08-18 23:11:19
【问题描述】:

我有一个 CSV 我要导入我们的数据库。其中一个“列”包含应该为 INT 的数据,但某些行的数字仅在 BIGINT 范围内(因为它们是来自我们合作伙伴之一的测试数据)。我们在内部存储 INT,不想更改。

我想安全地从 BIGINT 向下转换为 INT。安全地说,我的意思是如果发生算术溢出,则不应引发错误。如果转换/转换成功,我希望我的脚本继续。如果它失败了,我希望它短路。我似乎无法弄清楚正确的语法。这就是我所拥有的:

DECLARE @UserIDBigInt BIGINT = 9723021913; -- actually provided by query param
--Setting within the INT range successfully converts
--SET @UserIDBigInt = 5;
DECLARE @UserID INT = CONVERT(INT, @UserIDBigInt);
--DECLARE @UserID INT = CAST(@UserIDBigInt AS INT);
SELECT @UserIDBigInt
SELECT @UserID
IF @UserID IS NOT NULL BEGIN
    SELECT 'Handle it as reliable data'
END

我考虑过将@UserIDBigInt 与 INT 的有效范围(-2^31 (-2,147,483,648) 到 2^31-1 (2,147,483,647))进行比较,但我真的不喜欢这种方法。那是我的退路。我希望有一些我可以使用的语言结构或内置函数。如果我绝对必须与有效范围进行比较,是否至少有一些内置常量(如 C# 的 int.MinValue 和 int.MaxValue)?

编辑:更正错字。

【问题讨论】:

  • 没有内置常量。如果您最终想要与常量进行比较,这个问题之前已经回答过:stackoverflow.com/questions/7092774/…
  • 为什么不直接将值分配给存储过程中的 INT 变量,将该值直接分配回 BIGINT 变量,然后将 BIGINT 与原始值(也是 BIGINT)进行比较。如果分配给 INT 会发生溢出,则值将不匹配。
  • @Conspicuous 编译器,我从来没有说过我正在使用存储过程。无论如何,这样做会引发“将表达式转换为数据类型 int 的算术溢出错误”。正如我原来的问题中提到的那样。
  • 请删除一些没人会关注的无用标签,并用 RDBMS 和版本替换。假设 MS SQL Server 我知道的唯一可能有帮助的语言功能是SET ARITHABORT OFF; SET ANSI_WARNINGS OFF;
  • “我想安全地从 BIGINT 向下转换为 INT。安全地,我的意思是如果发生算术溢出,不应该引发错误。”这是什么意思?结果应该是什么 - 最大 int 值?什么都没有发生?

标签: sql sql-server tsql


【解决方案1】:

将这些添加到您的脚本中:

SET ARITHABORT OFF;
SET ARITHIGNORE ON;

这会将所有溢出值转换为 NULL。

更多信息在这里:http://msdn.microsoft.com/en-us/library/ms184341.aspx

【讨论】:

    【解决方案2】:

    bigint 转换为varbinary,然后将下半部分存储到@UserID 并检查上半部分:

    • 如果上半部分全为 0,下半部分表示非负值,则@UserID 则包含正确的int 值;

    • 如果上半部分全为1,@UserID为负数,也可以;

    • 否则会出现算术溢出。

    这是一个实现:

    DECLARE @UserIDBigInt BIGINT = 9723021913;
    DECLARE @UserID INT, @HighInt INT;
    
    WITH v AS (SELECT CAST(@UserIDBigInt AS varbinary) AS bin)
    SELECT
      @HighInt = SUBSTRING(bin, 1, 4),
      @UserID  = SUBSTRING(bin, 5, 4)
    FROM v;
    
    IF (@HighInt = 0 AND @UserID >= 0 OR @HighInt = -1 AND @UserID < 0) BEGIN
        SELECT 'Handle it as reliable data'
    END
    

    【讨论】:

      【解决方案3】:

      我不确定这是不是最好的答案,但这是我之前自己想出的。可以捕获异常/错误并优雅地继续执行。

      例子:

      DECLARE @UserIDBigInt BIGINT = 9723021913;
      DECLARE @UserID INT;
      BEGIN TRY
          SET @UserID = @UserIDBigInt;
      END TRY BEGIN CATCH
      END CATCH
      
      IF @UserID IS NULL BEGIN
          SELECT 'Handle it as unreliable data'
          RETURN
      END
      
      SELECT 'Handle it as reliable data'
      

      【讨论】:

        【解决方案4】:

        您还可以将值转换为字符串,将其修剪为长度并转换为 int。不是最好的方法,但肯定是一种安全简单的方法

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-06-14
          • 1970-01-01
          • 2012-07-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多