19

所以我只花了 5 个小时来解决一个问题,结果不仅是由于旧的不可靠 ISNUMERIC,而且看起来我的问题只出现在ISNUMERIC声明WITH SCHEMABINDING并在存储过程中调用的 UDF 时(我有很多将它提炼成一个测试用例需要做的工作,但我首先需要的是用可靠的东西替换它)。

任何关于ISNUMERIC(). 显然,确实需要对 , 等进行变体intmoney但是人们使用的是什么(最好在 T-SQL 中,因为在这个项目中,我仅限于 SQL Server,因为这是 SQL Server 到 SQL Server 数据的大容量 SQL Server处理任务)?

4

11 回答 11

24

如果您正在运行 SQL Server 2012,您可以使用 T-SQL 函数 TRY_CAST() 或 TRY_CONVERT(),正如 Bacon Bits 在评论中提到的那样:

SELECT CASE WHEN TRY_CAST('foo' AS INT) IS NULL THEN 0 ELSE 1 END

SELECT CASE WHEN TRY_CAST(1 AS INT) IS NULL THEN 0 ELSE 1 END

如果您使用的是 SQL 2008 R2 或更早版本,则必须使用 .NET CLR 函数并包装 System.Decimal.TryParse()。

于 2008-11-23T16:56:38.677 回答
16

根据验证的环境和性能特征,我有时会使用 LIKE 表达式的变体。例如:

NOT LIKE '%[^0-9]%'

请注意,这个具体的例子是相当幼稚的。它不保证该值对于转换为特定数据类型有效。如果您需要,它也不允许使用 +/- 符号或小数点。

于 2008-11-23T15:58:58.557 回答
6

另一种选择可能是用 C 等语言编写扩展存储过程,将其制成 DLL 并使其可用于 SQL Server。

我不认为这需要太多的代码行,而且它可能会比在 .NET 中编写托管存储过程更快,因为您不会因加载 CLR 而产生额外的意外。

这里有一些信息:http: //msdn.microsoft.com/en-us/library/ms175200.aspx

以下是一些可能对您有用的 C++ 代码:

using namespace std;

int checkNumber() {
  int number = 0;
  cin >> number;
  cin.ignore(numeric_limits<int>::max(), '\n');

  if (!cin || cin.gcount() != 1)
    cout << "Not a number.";
  else
    cout << "Your entered: " << number;
  return 0;
}
于 2009-01-27T20:49:39.800 回答
3

遵循 .NET CLR 路线,您可以使用正则表达式,尤其是在您期望一定范围的数字时。

SQL 2005 和正则表达式

于 2009-01-27T20:41:07.230 回答
2

通常作为一种实践,我尽量不要让无类型的数据进入数据库,因为它更适合在应用程序层处理它,或者在 SQL 集成服务中处理它,以便数据正确输入开始。

过去我不得不这样做很多次,通常最快的方法是编写自己的用户定义函数来验证数据是否符合您期望的格式,因为大多数时候调用扩展存储过程的开销或用于简单验证的托管代码比仅在 T-SQL 中执行要慢。

于 2008-11-23T13:15:02.837 回答
1

根据 Microsoft 的支持,唯一有效的替换 UDF 函数的方法是编写自己的 .NET 函数版本。

当然,如果您的数据库管理员允许 :)。

我的没有:(。

于 2008-11-23T15:24:49.190 回答
1

如何实现这两个功能:

CREATE FUNCTION dbo.isReallyNumeric  
(  
    @num VARCHAR(64)  
)  
RETURNS BIT  
BEGIN  
    IF LEFT(@num, 1) = '-'  
        SET @num = SUBSTRING(@num, 2, LEN(@num))  

    DECLARE @pos TINYINT  

    SET @pos = 1 + LEN(@num) - CHARINDEX('.', REVERSE(@num))  

    RETURN CASE  
    WHEN PATINDEX('%[^0-9.-]%', @num) = 0  
        AND @num NOT IN ('.', '-', '+', '^') 
        AND LEN(@num)>0  
        AND @num NOT LIKE '%-%' 
        AND  
        (  
            ((@pos = LEN(@num)+1)  
            OR @pos = CHARINDEX('.', @num))  
        )  
    THEN  
        1  
    ELSE  
    0  
    END  
END  
GO  

CREATE FUNCTION dbo.isReallyInteger  
(  
    @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  
GO

原始来源

于 2009-01-30T09:44:15.487 回答
1

对于 SQL Server 2005 及更高版本....利用 try/catch...

declare @test varchar(10), @num decimal
select @test = '0123A'

begin try
    select @num = cast(@test as decimal)
    print '1'
end try 
begin catch
    print '0'
end catch

打印 0。

更改 @test = '01234' 或 @test = '01234.5' 并打印 1。

于 2010-03-24T18:23:43.553 回答
0

您是否会处理您自己的(人类)语言之外的数字系统,例如中文等?如果是这样,我建议使用libuninum library

于 2008-11-23T08:22:46.310 回答
0

IsNumeric() 似乎对空格、'D'、'E'、美元符号和各种其他字符有问题。我们通常想要的是告诉我们 CAST 或 CONVERT 是否会成功的东西。这个 UDF 虽然不是最快的解决方案,但对我来说效果很好。

create function dbo.udf_IsNumeric(@str varchar(50))
  returns int
as
begin
  declare @rtn int
  select @rtn =
    case
      when ltrim(rtrim(@str)) in('.', '-', '-.', '+', '+.') then 0
      when ltrim(rtrim(@str)) like '%[^-+.0-9]%' then 0
      else isnumeric(@str)
    end
  return @rtn
end
于 2009-10-17T02:02:28.913 回答
0

从 SQL 2012 开始,您可以使用 TRY_PARSE() 函数代替 ISNUMERIC()。

SELECT
 TRY_PARSE('123' as int) as '123'
,TRY_PARSE('abc' as int) as 'abc'
于 2015-10-07T11:02:25.397 回答