这应该处理所有情况而不抛出任何异常:
--This handles dollar-signs, commas, decimal-points, and values too big or small,
-- all while safely returning an int.
DECLARE @IntString as VarChar(50) = '$1,000.'
SELECT CAST((CASE WHEN --This IsNumeric check here does most of the heavy lifting. The rest is Integer-Specific
ISNUMERIC(@IntString) = 1
--Only allow Int-related characters. This will exclude things like 'e' and other foreign currency characters.
AND @IntString NOT LIKE '%[^ $,.\-+0-9]%' ESCAPE '\'--'
--Checks that the value is not out of bounds for an Integer.
AND CAST(REPLACE(REPLACE(@IntString,'$',''),',','') as Decimal(38)) BETWEEN -2147483648 AND 2147483647
--This allows values with decimal-points for count as an Int, so long as there it is not a fractional value.
AND CAST(REPLACE(REPLACE(@IntString,'$',''),',','') as Decimal(38)) = CAST(REPLACE(REPLACE(@IntString,'$',''),',','') as Decimal(38,2))
--This will safely convert values with decimal points to casting later as an Int.
THEN CAST(REPLACE(REPLACE(@IntString,'$',''),',','') as Decimal(10))
END) as Int)[Integer]
将其放入标量 UDF 中并调用它ReturnInt()。
如果该值返回为 NULL,则它不是 int(因此有您的 IsInteger() 要求)
如果您不喜欢输入“WHERE ReturnInt(SomeValue) IS NOT NULL”,您可以将其放入另一个名为 IsInt() 的标量 UDF 中来调用它函数并简单地返回“ReturnInt(SomeValue) IS NOT NULL”。
很酷的是,UDF 可以通过返回“安全”转换的 int 值来提供双重任务。
仅仅因为 可以 是 int 并不意味着将其转换为 int 不会引发巨大的异常。这会为您解决这个问题。
另外,我会避免使用其他解决方案,因为这种通用方法将处理逗号、小数、美元符号,并检查可接受的 Int 值的范围,而其他解决方案则不这样做 - 或者它们需要多个 SET 操作来阻止您使用标量函数中的逻辑以获得最佳性能。
查看下面的示例并针对我的代码和其他代码进行测试:
--Proves that appending "e0" or ".0e0" is NOT a good idea.
select ISNUMERIC('$1' + 'e0')--Returns: 0.
select ISNUMERIC('1,000' + 'e0')--Returns: 0.
select ISNUMERIC('1.0' + '.0e0')--Returns: 0.
--While these are numeric, they WILL break your code
-- if you try to cast them directly as int.
select ISNUMERIC('1,000')--Returns: 1.
select CAST('1,000' as Int)--Will throw exception.
select ISNUMERIC('$1')--Returns: 1.
select CAST('$1' as Int)--Will throw exception.
select ISNUMERIC('10.0')--Returns: 1.
select CAST('10.0' as Int)--Will throw exception.
select ISNUMERIC('9999999999223372036854775807')--Returns: 1. This is why I use Decimal(38) as Decimal defaults to Decimal(18).
select CAST('9999999999223372036854775807' as Int)--Will throw exception.
更新:
我在这里阅读了一条评论,您希望能够解析像“123”这样的值。成一个整数。我也更新了我的代码来处理这个问题。
注意:这会转换“1.0”,但会在“1.9”上返回 null。
如果您想允许舍入,则调整“THEN”子句中的逻辑以添加 Round(),如下所示:
ROUND(CAST(REPLACE(REPLACE(@IntString,'$',''),',','') as Decimal(10)), 0)
您必须还删除检查“小数点”的“AND”以允许舍入或截断。