我在SQL2000上安全地将varchar
转换为int
时遇到了一些问题。
我的问题的第1部分是IsNumeric returns false positives,如果你只寻找整数。我知道为什么IsNumeric会这样做(浮点数,钱等也是数字)所以我在google上寻找IsInteger
函数。
我找到了以下用户定义函数(UDF):
CREATE FUNCTION dbo.IsInteger
(
@num VARCHAR(64)
)
RETURNS BIT
BEGIN
IF LEFT(@num, 1) = '-'
SET @num = SUBSTRING(@num, 2, LEN(@num))
RETURN CASE
WHEN PATINDEX('%[^0-9-]%', @num) = 0
AND CHARINDEX('-', @num) <= 1
AND @num NOT IN ('.', '-', '+', '^')
AND LEN(@num)>0
AND @num NOT LIKE '%-%'
THEN
1
ELSE
0
END
END
这似乎可以很好地检查整数:
declare @num varchar(256);
declare @num2 varchar(256);
set @num = '22312311';
set @num2 = '22312311.0';
SELECT @num AS [character],
dbo.IsInteger(@num) AS [isInteger],
CASE dbo.IsInteger(@num)WHEN 1 THEN convert(int, @num) ELSE NULL END AS [integer]
UNION
SELECT @num2 AS [character],
dbo.IsInteger(@num2) AS [isInteger],
CASE dbo.IsInteger(@num2)WHEN 1 THEN convert(int, @num2) ELSE NULL END AS [integer];
然而,它不会验证整数是否在范围(-2^31 <=> 2^31 - 1
)
declare @num varchar(256);
set @num = '2147483648';
SELECT @num AS [character],
dbo.IsInteger(@num) AS [isInteger],
CASE dbo.IsInteger(@num)WHEN 1 THEN convert(int, @num) ELSE NULL END AS [integer];
哪个投掷
Server: Msg 248, Level 16, State 1, Line 3
The conversion of the nvarchar value '2147483648' overflowed an int column. Maximum integer value exceeded.
SQL2000 doesn't have TRY/CATCH(回答假设ISNUMERIC()不返回误报)并且根据this website,即使在UDF中,整个批处理也会导致整个批处理失败:
当UDF发生错误时, 该函数的执行被中止 立即,所以查询,和 除非错误是中止的错误 批处理,继续执行 下一个陈述 - 但是@@ error是0!
即使他们不这样做仍然会模糊@@error
。我也无法转换为bigint
,因为它可能仍会崩溃(虽然不常见),并且此查询是输出到XML的UNION的一部分,它通过VB6 COM DLL进一步验证并使用XSLT进行转换,显示在2001年编码的网站上,所以我真的(没有真的)不想更改查询输出!。
所以这让我陷入了这个看似简单的任务:
如果varchar可以转换为int cast to int,否则给我NULL
任何指针/解决方案都会非常复杂,但请注意,在任何情况下,我都不能更改源列的数据类型,也不能在输入数据时更改验证。
答案 0 :(得分:4)
编辑:
您的数字不能超过decimal(38,0) in SQL Server(+/- 10 ^ 38 -1),因此无法捕获或转换它们。这意味着37个字符可能长度,CAST到十进制(38,0)
SELECT
CASE
WHEN CAST(MyColumn AS decimal(38,0) BETWEEN -2147483648 AND 2147483647 THEN CAST(MyColumn AS int)
ELSE NULL
END
FROM
MyTable
WHERE
ISNUMERIC(MyColumn + '.0e0') = 1 AND LEN(MyColumn) <= 37
尊重this article .0e0技巧
编辑OP
这个问题引导我进入下面更新的IsInteger函数。
CREATE FUNCTION dbo.IsInteger
(
@num VARCHAR(256)
)
RETURNS BIT
BEGIN
RETURN CASE
WHEN ISNUMERIC(@num + '.0e0') = 1 AND convert(decimal(38,0), @num) BETWEEN -2147483648 AND 2147483647 THEN 1
ELSE 0
END
END
答案 1 :(得分:0)
您可以在函数中添加几个检查:
CREATE FUNCTION [dbo].[IsInteger]
(
@num VARCHAR(64)
)
RETURNS BIT
BEGIN
IF LEFT(@num, 1) = '-'
SET @num = SUBSTRING(@num, 2, LEN(@num))
DECLARE @IsInt BIT
SELECT @IsInt = CASE
WHEN PATINDEX('%[^0-9-]%', @num) = 0
AND CHARINDEX('-', @num) <= 1
AND @num NOT IN ('.', '-', '+', '^')
AND LEN(@num)>0
AND @num NOT LIKE '%-%'
THEN
1
ELSE
0
END
IF @IsInt = 1
BEGIN
IF LEN(@num) <= 11
BEGIN
DECLARE @test bigint
SELECT @test = convert(bigint, @num)
IF @test <= 2147483647 AND @test >= -2147483648
BEGIN
set @IsInt = 1
END
ELSE
BEGIN
set @IsInt = 0
END
END
ELSE
BEGIN
set @IsInt = 0
END
END
RETURN @IsInt
END
我没有机会参加测试,但我认为它应该可行 - 我已经尽可能详细地将其保留了