检查一个varchar是否为数字(T-SQL)

74

有没有一种简单的方法来确定一个varchar是否为数字?

示例:

abc123 --> 不是数字

123 --> 是数字


4
"Isnumeric"函数存在很多怪异的问题(参见 https://connect.microsoft.com/SQLServer/feedback/details/302466/isnumeric-returns-true-for-and)。 - Martin Smith
1
我在上方添加了一个链接,其中包含一些示例和微软的解释。您需要匹配哪些数字格式?例如,您是否需要匹配类似于“1e23”的内容? - Martin Smith
在处理 IsNumeric 的怪异情况时,考虑使用 TRY_CAST(ReqCol As INT) IS NOT NULL 如何? - Sai
1
请接受达米恩的答案。 - greg121
12个回答

157

ISNUMERIC不适用 - 它告诉您该字符串可以转换为任何数值类型,这几乎总是一种无意义的信息。例如,根据ISNUMERIC以下所有内容都是数值:

£、$、0d0

如果您想检查数字且仅有数字,则需要使用负LIKE表达式:

not Value like '%[^0-9]%'

2
ISNUMERIC函数也将“-”视为数字。 - Ewald Stieger
1
如果您只需要正整数,那么这是一个很好的方法,但如果您需要允许其他类型的数字,则可以使用SQL 2012+。下面我添加了一些示例。 - Dan Field
绝对比ISNUMERIC更好的答案!这应该被标记为正确答案。 - iaforek
这个和其他类似的答案会说原始问题中的第一个例子是一个数字,因为它的字符之一是一个数字。那么如果你想知道所有字符都是数字呢? - RosieC
@RosieC - 不,我代码中的例子 not Value like '%[^0-9]%' 意思是所有字符都是数字。这是一个双重否定。它断言 Value 中没有任何字符超出了 0-9 的范围。 - Damien_The_Unbeliever
3
@RosieC - 或者换句话说,Value like '%[0-9]%' 将是“字符串包含至少一个数字字符”。Value like '%[^0-9]%' 将是“字符串包含至少一个非数字字符”。但是,再次强调,我的测试是 not Value like '%[^0-9]%',它否定了先前的测试,即“字符串不包含非数字字符”。 - Damien_The_Unbeliever

37

ISNUMERIC 可以实现此功能。

还要查看文章中的 NOTES 部分。


8
@Grady - 我认为下面的Damien的回答更好,因为他指出了IsNumeric确实有一些限制。你确定自己没有遇到任何这样的限制吗? - Sachin Shanbhag
3
好的,我会尽力进行翻译。请提供需要翻译的内容。 - greg121
4
"select isnumeric('138D47')" 的返回值为1。 - marknuzz
1
-1 很多东西是数字,但如果转换为INT或Float会出现异常--请参见https://www.brentozar.com/archive/2018/02/fifteen-things-hate-isnumeric,其中显示以下15个字符串都是“IsNumeric”=1 '$' ,'£' ,',' ,'.' ,'0e+99' ,'2e2' ,'12D4' ,',1,1,1,1,1,1,1' ,'-' ,'+' ,CHAR(9) ,CHAR(10) ,CHAR(11) ,CHAR(12) ,CHAR(13)。 - Andrew Hill
@Nuzzolilo 因为如果它是十六进制的东西,它似乎是数字,而且 d 是十六进制的一部分。 - Valentin C
我仍然在以下查询中遇到错误Declare @testVal as varchar(50)='ok' select CASE WHEN IsNUMERIC(@testVal)=1 THEN Cast(@testVal as numeric) ELSE 'n' End将varchar数据类型转换为numeric时出错。 - Ketan Vaghasiya

32

你可以这样检查:

declare @vchar varchar(50)
set @vchar ='34343';
select case when @vchar not like '%[^0-9]%' then 'Number' else 'Not a Number' end

25

如果你有特定的需求,使用SQL Server 2012+,你可以使用TRY_*函数。例如,

-- will fail for decimal values, but allow negative values
TRY_CAST(@value AS INT) IS NOT NULL 

-- will fail for non-positive integers; can be used with other examples below as well, or reversed if only negative desired
TRY_CAST(@value AS INT) > 0

-- will fail if a $ is used, but allow decimals to the specified precision
TRY_CAST(@value AS DECIMAL(10,2)) IS NOT NULL 

-- will allow valid currency
TRY_CAST(@value AS MONEY) IS NOT NULL  

-- will allow scientific notation to be used like 1.7E+3
TRY_CAST(@value AS FLOAT) IS NOT NULL 

1
这是最好的解决方案。使用 %[^0-9.]% 的解决方案似乎会在字符串中包含数字和其他字符时返回说它是一个数字。这个 TRY_CAST 对我很有效。 - RosieC
2
请记住,它需要 SQL Server 2012 或更高版本 - 在 2008R2 或更低版本上无法工作,并且在其他 RDBMS 中也无法工作。 - Dan Field

9

我遇到了需要允许小数值的情况,所以我使用了not Value like '%[^0-9.]%'

。该方法可以实现只允许数字和小数点输入的效果。


这不太好。它只会与., 2.2.2...1....0, 2.1.2等匹配。你需要添加第二个条件来排除有多个小数点或小数点不在两个数字之间的情况。 - The_Rafi

3

Wade73 的小数解决方案并不完美。我修改了它,只允许一个小数点。

declare @MyTable table(MyVar nvarchar(10));
insert into @MyTable (MyVar)
values
    (N'1234')
    , (N'000005')
    , (N'1,000')
    , (N'293.8457')
    , (N'x')
    , (N'+')
    , (N'293.8457.')
    , (N'......');

-- This shows that Wade73's answer allows some non-numeric values to slip through.
select * from (
    select
        MyVar
        , case when MyVar not like N'%[^0-9.]%' then 1 else 0 end as IsNumber
    from
        @MyTable
) t order by IsNumber;

-- Notice the addition of "and MyVar not like N'%.%.%'".
select * from (
    select
        MyVar
        , case when MyVar not like N'%[^0-9.]%' and MyVar not like N'%.%.%' then 1 else 0 end as IsNumber
    from
        @MyTable
) t
order by IsNumber;

我不得不添加 <> '.' 幸运的是,我的数据中没有一个 '-' 放错了位置。 - Colin

2

Damien_The_Unbeliever指出,这种方式只适用于数字

Wade73添加了一些内容以处理小数点

neizan进行了另一个微调,而did notwhereuareat也做了相似的微调。

不幸的是,以上方法似乎都无法处理负值和带有逗号的值...

以下是我的微调,可识别负数和带有逗号的值。

declare @MyTable table(MyVar nvarchar(10));
insert into @MyTable (MyVar) 
values 
(N'1234')
, (N'000005')
, (N'1,000')
, (N'293.8457')
, (N'x')
, (N'+')
, (N'293.8457.')
, (N'......')
, (N'.')
, (N'-375.4')
, (N'-00003')
, (N'-2,000')
, (N'3-3')
, (N'3000-')
;

-- This shows that Neizan's answer allows "." to slip through.
select * from (
select 
    MyVar
    , case when MyVar not like N'%[^0-9.]%' then 1 else 0 end as IsNumber 
from 
    @MyTable
) t order by IsNumber;

-- Notice the addition of "and MyVar not like '.'".
select * from (
select 
    MyVar
    , case when MyVar not like N'%[^0-9.]%' and MyVar not like N'%.%.%' and MyVar not like '.' then 1 else 0 end as IsNumber 
from 
    @MyTable
) t 
order by IsNumber;

--Trying to tweak for negative values and the comma
--Modified when comparison
select * from (
select 
    MyVar
    , case 
        when MyVar not like N'%[^0-9.,-]%' and MyVar not like '.' and isnumeric(MyVar) = 1 then 1
        else 0 
    end as IsNumber 
from 
    @MyTable
) t 
order by IsNumber;

1
DECLARE @A nvarchar(100) = '12'
IF(ISNUMERIC(@A) = 1)
BEGIN
    PRINT 'YES NUMERIC'
END

1

Neizan的代码 允许只有一个 "." 的值通过。为了避免过于学究,我添加了一个AND子句。

declare @MyTable table(MyVar nvarchar(10));
insert into @MyTable (MyVar) 
values 
    (N'1234')
    , (N'000005')
    , (N'1,000')
    , (N'293.8457')
    , (N'x')
    , (N'+')
    , (N'293.8457.')
    , (N'......')
    , (N'.')
    ;

-- This shows that Neizan's answer allows "." to slip through.
select * from (
    select 
        MyVar
        , case when MyVar not like N'%[^0-9.]%' then 1 else 0 end as IsNumber 
    from 
        @MyTable
) t order by IsNumber;

-- Notice the addition of "and MyVar not like '.'".
select * from (
    select 
        MyVar
        , case when MyVar not like N'%[^0-9.]%' and MyVar not like N'%.%.%' and MyVar not like '.' then 1 else 0 end as IsNumber 
    from 
        @MyTable
) t 
order by IsNumber;

0

要检查数字、货币和金额,请使用下面的SQL片段。

@value NOT LIKE '%[^0-9.,]%'

为了快速取得成功,请参考以下示例:

函数示例:

CREATE FUNCTION [dbo].[fnCheckValueIsNumber](
    @value NVARCHAR(255)=NULL
)RETURNS INT  AS BEGIN
    DECLARE @ReturnValue INT=0
    IF EXISTS (SELECT * WHERE @value NOT LIKE '%[^0-9.,]%') SELECT @ReturnValue=1
RETURN @ReturnValue;

执行结果

SELECT [dbo].[fnCheckValueIsNumber]('12345')
RESULT = 1

SELECT [dbo].[fnCheckValueIsNumber]('10020.25')
RESULT = 1

SELECT [dbo].[fnCheckValueIsNumber]('10,020.25')
RESULT = 1

SELECT [dbo].[fnCheckValueIsNumber]('12,345ABCD')
RESULT = 0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接