【问题标题】:Preventing Sql column overflows防止 Sql 列溢出
【发布时间】:2009-04-14 15:52:29
【问题描述】:

如果我有一个参数化存储过程,它采用 varchar(10) 值并将其转换为 int,我目前必须确保该值不大于最大 int 值的 varchar 等效值。

IF @Criteria <= '2147483647'
    SET @Id = CONVERT(int, @Criteria)

我的问题:从 varchar 值转换时,有没有更好的方法来防止 int 列溢出?

编辑:是的,很明显,如果我觉得 a 值将合法地包含接近最大值的东西,我可以扩展到 BigInt。这实际上是为了处理对此存储过程的不正确调用,并且只是一个关于在结果值可能溢出所需数据类型的情况下使用 Convert() 的通用问题。

【问题讨论】:

    标签: sql sql-server database stored-procedures


    【解决方案1】:

    为了处理各种条件(空格、小数等),如果您无法在客户端上清理,请将转换包装在 TRY/CATCH 中。假设 SQL Server 2005

    ...
    BEGIN TRY
       SET @Id = CONVERT(int, @Criteria)
    END TRY
    BEGIN CATCH
       SET @Id = NULL
    END CATCH
    ...
    

    【讨论】:

      【解决方案2】:

      您的测试将无法可靠运行。

      如果@Criteria 包含“11111111111111111111”,则排序小于您的幻数,因为您正在进行字符串比较。

      【讨论】:

        【解决方案3】:

        最简单和最好的方法是在源头处理它,也就是创建 varchar 的地方。或者解释一下“防止溢出”是什么意思。当 varchar 实际上太长时,您期望会发生什么?

        【讨论】:

        • 预期的结果是存储过程不返回任何行,而不是在我的数据库阅读器中导致异常,但我只是要在客户端上做更多的验证,正如 gbn 建议的那样.
        【解决方案4】:

        如果你传入空格怎么办? - 它将通过 IF 条件但转换失败。您也应该使用 ISNUMERIC ()。

        IF @Criteria <= '2147483647' AND ISNUMERIC(@Criteria)
                SET @Id = CONVERT(int, @Criteria)
        

        【讨论】:

          【解决方案5】:

          一个更好的问题可能是您为什么将整数存储为 varchars 会溢出其目标列。我不太确定你能做些什么来完全防止溢出;您可以考虑将 Id 切换为无符号整数,这样您最多可以获得 2^32 位可用(我猜 Criteria 永远不会是负数,因为您将它分配给 Id 列)。

          我不确定 SQL Server 是否支持它,但 MySQL 有 BIGINT 列,最高可达 2^64(如果你想签名,则为 2^63)。

          【讨论】:

          • SQL Server 确实支持有符号的 bigint(-2^63 到 2^63-1)。
          【解决方案6】:

          首先,您的输入长度 10 看起来您不期望(或接受)负值。 int 的下限是 -2147483648,它将由 11 个字符的字符串表示。

          基于上面 DJ 的代码,我建议您将 ISNUMERIC() 调用放在 CONVERT/compare 之前。

          IF ISNUMERIC(@Criteria) = 1
            AND CONVERT(bigint, @Criteria) <=  2147483647
                  SET @Id = CONVERT(int, @Criteria)
          

          这首先转换为 bigint,然后进行比较。以下是一些测试用例:

          DECLARE @Id         int
          DECLARE @Criteria   varchar(10)
          
          PRINT 'Expect failure (NULL)'
          SET @Criteria = '2147483648'
          SET @Id = NULL
          
          IF ISNUMERIC(@Criteria) = 1
            AND CONVERT(bigint, @Criteria) <=  2147483647
                  SET @Id = CONVERT(int, @Criteria)
          
          SELECT @Id AS '@Id', @Criteria AS '@Criteria', CONVERT(bigint, @Criteria) AS 'Converted to bigint'
          
          PRINT 'Expect success'
          SET @Criteria = '2147483647'
          SET @Id = NULL
          
          IF ISNUMERIC(@Criteria) = 1
            AND CONVERT(bigint, @Criteria) <=  2147483647
                  SET @Id = CONVERT(int, @Criteria)
          
          SELECT @Id AS '@Id', @Criteria AS '@Criteria', CONVERT(bigint, @Criteria) AS 'Converted to bigint'
          
          PRINT 'Expect failure but get success because @Criteria is truncated to 10 characters'
          SET @Criteria = '11111111111111111111'
          SET @Id = NULL
          
          IF ISNUMERIC(@Criteria) = 1
            AND CONVERT(bigint, @Criteria) <= 2147483647
                  SET @Id = CONVERT(int, @Criteria)
          
          SELECT @Id AS '@Id', @Criteria AS '@Criteria', CONVERT(bigint, @Criteria) AS 'Converted to bigint'
          

          和结果:

          Expect failure (NULL)
                  @Id @Criteria   Converted to bigint
          ----------- ---------- --------------------
                 NULL 2147483648           2147483648
          
          Expect success
                  @Id @Criteria   Converted to bigint
          ----------- ---------- --------------------
           2147483647 2147483647           2147483647
          
          Expect failure but get success because @Criteria is truncated to 10 characters
                  @Id @Criteria   Converted to bigint
          ----------- ---------- --------------------
           1111111111 1111111111           1111111111
          

          请注意,由于输入被截断,因此传递 '11111111111111111111' 实际上有效。

          【讨论】:

          • 这在浮点数、十进制数、嵌入空格以及许多其他情况下可能会失败。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-09-16
          • 1970-01-01
          • 2014-03-05
          相关资源
          最近更新 更多