Efficient ISNUMERIC() replacements on SQL Server?

后端 未结 11 2002
失恋的感觉
失恋的感觉 2020-11-27 06:02

So I just spent 5 hours troubleshooting a problem which turned out to be due not only to the old unreliable ISNUMERIC but it looks like my problem only appears

相关标签:
11条回答
  • 2020-11-27 06:55

    Following the .NET CLR route, you could go with a regular expression, particularly if you expect a certain range of numbers.

    SQL 2005 and Regular Expressions

    0 讨论(0)
  • 2020-11-27 06:59

    Depending on the circumstances and the performance characteristics of the validation, I sometimes use a variation of the LIKE expression instead. For example:

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

    Note that this specific example is fairly naive. It doesn't guarantee that the value is valid for conversion to a particular data type. It also doesn't allow for +/- signs or decimal points if you need those.

    0 讨论(0)
  • 2020-11-27 07:02

    How about implementing these two functions:

    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
    

    Original Source

    0 讨论(0)
  • 2020-11-27 07:04

    You can use the T-SQL functions TRY_CAST() or TRY_CONVERT() if you're running SQL Server 2012 as Bacon Bits mentions in the comments:

    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
    

    If you're using SQL 2008 R2 or older, you'll have to use a .NET CLR function, and wrap System.Decimal.TryParse().

    0 讨论(0)
  • 2020-11-27 07:06

    Generally as a practice, I try not to let untyped data into the database, as it is better more suited to either handle it at the application layer, or for batch imports handle it in SQL Integration Services so that the data comes in typed correctly from the start.

    I have had to do it many times in the past and usually the fastest way is to write your own user defined function to verify the data is in the format you expect, as most of the time the overhead to calling out to an extended stored proc or managed code for simple validation is slower than just doing it in T-SQL.

    0 讨论(0)
提交回复
热议问题