防止Sql列溢出

时间:2009-04-14 15:52:29

标签: sql sql-server database stored-procedures

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

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

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

编辑:是的,如果我觉得该值合法地包含接近最大值的值,我可以扩展到BigInt。这实际上意味着处理对此存储过程的不正确调用,并且只是在结果值可能溢出所需数据类型的情况下使用Convert()的一般目的问题。

6 个答案:

答案 0 :(得分:3)

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

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

答案 1 :(得分:3)

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

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

答案 2 :(得分:1)

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

答案 3 :(得分:1)

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

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

答案 4 :(得分:1)

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

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

答案 5 :(得分:1)

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

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

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'实际上是有效的,因为输入被截断了。