【问题标题】:TSQL - Cast string to integer or return default valueTSQL - 将字符串转换为整数或返回默认值
【发布时间】:2011-01-01 06:50:37
【问题描述】:

在 T-SQL 中有没有办法将 nvarchar 转换为 int 并在转换失败时返回默认值或 NULL?

【问题讨论】:

    标签: sql tsql


    【解决方案1】:

    是的:)。试试这个:

    DECLARE @text AS NVARCHAR(10)
    
    SET @text = '100'
    SELECT CASE WHEN ISNUMERIC(@text) = 1 THEN CAST(@text AS INT) ELSE NULL END
    -- returns 100
    
    SET @text = 'XXX'
    SELECT CASE WHEN ISNUMERIC(@text) = 1 THEN CAST(@text AS INT) ELSE NULL END
    -- returns NULL
    

    ISNUMERIC() 有一些Fedor Hajdu 指出的问题。

    对于$(是货币)、,.(两者都是分隔符)、+- 等字符串返回 true。

    【讨论】:

    • 感谢您的回答。我希望有更优雅的东西。
    • 当文本值是数字,但包含大于 int 列可以存储的数字时怎么办?
    • -1:不幸的是,ISNUMERIC 存在太多问题,因此这个答案对未经验证的数据没有任何用处(而且您首先不需要 ISNUMERIC 检查正确验证的数据)。作者承认这些问题的存在,但没有解决它们。
    • 作为Joseph Mentions,SQL 2012+的用户应该使用TRY_CONVERT/TRY_CAST,这是为了解决OP的问题。此答案是在 SQL 2012 发布之前编写的。
    • 我投了反对票,因为 ISNUMERIC('1,1,1,1,1') = 1 并且这永远不会转换为 int。
    【解决方案2】:

    如果您使用的是 SQL Server 2012(或更高版本):

    使用TRY_CONVERT function

    如果您使用的是 SQL Server 2005、2008 或 2008 R2:

    创建一个用户定义的函数。这将避免Fedor Hajdu mentioned 在货币、小数等方面的问题:

    CREATE FUNCTION dbo.TryConvertInt(@Value varchar(18))
    RETURNS int
    AS
    BEGIN
        SET @Value = REPLACE(@Value, ',', '')
        IF ISNUMERIC(@Value + 'e0') = 0 RETURN NULL
        IF ( CHARINDEX('.', @Value) > 0 AND CONVERT(bigint, PARSENAME(@Value, 1)) <> 0 ) RETURN NULL
        DECLARE @I bigint =
            CASE
            WHEN CHARINDEX('.', @Value) > 0 THEN CONVERT(bigint, PARSENAME(@Value, 2))
            ELSE CONVERT(bigint, @Value)
            END
        IF ABS(@I) > 2147483647 RETURN NULL
        RETURN @I
    END
    GO
    
    -- Testing
    DECLARE @Test TABLE(Value nvarchar(50))    -- Result
    INSERT INTO @Test SELECT '1234'            -- 1234
    INSERT INTO @Test SELECT '1,234'           -- 1234
    INSERT INTO @Test SELECT '1234.0'          -- 1234
    INSERT INTO @Test SELECT '-1234'           -- -1234
    INSERT INTO @Test SELECT '$1234'           -- NULL
    INSERT INTO @Test SELECT '1234e10'         -- NULL
    INSERT INTO @Test SELECT '1234 5678'       -- NULL
    INSERT INTO @Test SELECT '123-456'         -- NULL
    INSERT INTO @Test SELECT '1234.5'          -- NULL
    INSERT INTO @Test SELECT '123456789000000' -- NULL
    INSERT INTO @Test SELECT 'N/A'             -- NULL
    SELECT Value, dbo.TryConvertInt(Value) FROM @Test
    

    参考:我在创建解决方案时广泛使用了this page

    【讨论】:

    • 有人能用它吗?我按照建议创建了一个函数,发现它使用建议的测试函数会引发转换错误。我想我在这里遗漏了一些东西......
    • @JosephSturtevant 这很漂亮
    • 是的,干得好...为我节省了很多工作...由于客户的原因,我不在 2012 年或更高...不过不要给我信用 :) 我只是很好在寻找对我有用的答案时......虽然我将它从返回 null 更改为返回零,因为愚蠢的 varchar 应该是一个默认为零的 int 列:)
    【解决方案3】:

    我宁愿创建一个像 TryParse 这样的函数,或者使用 T-SQL TRY-CATCH 块来获得你想要的。

    ISNUMERIC 并不总是按预期工作。如果你这样做,之前给出的代码将失败:

    SET @text = '$'

    $ 符号可以转换为货币数据类型,因此 ISNUMERIC() 在这种情况下返回 true。它对'-'(减号)、','(逗号)和'.'也一样。字符。

    【讨论】:

    • True :(。ISNUMERIC() 返回1 也适用于,.
    • ...除非您不能在函数内使用 TRY-CATCH(至少不能在我的 SQL 2005 数据库中)...link
    【解决方案4】:

    如前所述,如果您使用ISNUMERIC,您可能会遇到几个问题:

    -- Incorrectly gives 0:
    SELECT CASE WHEN ISNUMERIC('-') = 1 THEN CAST('-' AS INT) END   
    
    -- Error (conversion failure):
    SELECT CASE WHEN ISNUMERIC('$') = 1 THEN CAST('$' AS INT) END
    SELECT CASE WHEN ISNUMERIC('4.4') = 1 THEN CAST('4.4' AS INT) END
    SELECT CASE WHEN ISNUMERIC('1,300') = 1 THEN CAST('1,300' AS INT) END
    
    -- Error (overflow):
    SELECT CASE WHEN ISNUMERIC('9999999999') = 1 THEN CAST('9999999999' AS INT) END
    

    如果您想要可靠的转换,您需要自己编写代码。

    更新:我的新建议是使用中间测试转换为FLOAT 来验证号码。这种方法基于adrianm's comment。逻辑可以定义为内联表值函数:

    CREATE FUNCTION TryConvertInt (@text NVARCHAR(MAX)) 
    RETURNS TABLE
    AS
    RETURN
    (
        SELECT
            CASE WHEN ISNUMERIC(@text + '.e0') = 1 THEN 
                 CASE WHEN CONVERT(FLOAT, @text) BETWEEN -2147483648 AND 2147483647 
                      THEN CONVERT(INT, @text) 
                 END 
             END AS [Result]
    )
    

    一些测试:

    SELECT [Conversion].[Result]
    FROM ( VALUES
         ( '1234'                     )   -- 1234
       , ( '1,234'                    )   -- NULL
       , ( '1234.0'                   )   -- NULL
       , ( '-1234'                    )   -- -1234
       , ( '$1234'                    )   -- NULL
       , ( '1234e10'                  )   -- NULL
       , ( '1234 5678'                )   -- NULL
       , ( '123-456'                  )   -- NULL
       , ( '1234.5'                   )   -- NULL
       , ( '123456789000000'          )   -- NULL
       , ( 'N/A'                      )   -- NULL
       , ( '-'                        )   -- NULL
       , ( '$'                        )   -- NULL
       , ( '4.4'                      )   -- NULL
       , ( '1,300'                    )   -- NULL
       , ( '9999999999'               )   -- NULL
       , ( '00000000000000001234'     )   -- 1234
       , ( '212110090000000235698741' )   -- NULL
    ) AS [Source] ([Text])
    OUTER APPLY TryConvertInt ([Source].[Text]) AS [Conversion]
    

    结果与Joseph Sturtevant's answer类似,主要区别如下:

    • 我的逻辑不允许出现., 以模仿本机INT 转换的行为。 '1,234''1234.0' 返回 NULL
    • 由于不使用局部变量,我的函数可以定义为内联表值函数,从而实现更好的查询优化。
    • Joseph 的回答可能会由于参数的静默截断而导致不正确的结果; '00000000000000001234' 计算结果为 12。增加参数长度会导致溢出BIGINT的数字出错,比如BBANs(基本银行帐号)比如'212110090000000235698741'

    撤回:不再推荐以下方法,仅供参考。

    下面的 sn-p 适用于非负整数。它检查您的字符串不包含任何非数字字符、不为空且不溢出(通过超过 int 类型的最大值)。但是,它也会为由于前导零而长度超过 10 个字符的有效整数提供NULL

    SELECT 
        CASE WHEN @text NOT LIKE '%[^0-9]%' THEN
             CASE WHEN LEN(@text) BETWEEN 1 AND 9 
                    OR LEN(@text) = 10 AND @text <= '2147483647' 
                  THEN CAST (@text AS INT)
             END
        END 
    

    如果您想支持任意数量的前导零,请使用以下内容。嵌套的 CASE 语句虽然笨重,但需要促进短路评估并减少错误的可能性(例如,由于将负长度传递给 LEFT)。

    SELECT 
        CASE WHEN @text NOT LIKE '%[^0-9]%' THEN
             CASE WHEN LEN(@text) BETWEEN 1 AND 9 THEN CAST (@text AS INT)
                  WHEN LEN(@text) >= 10 THEN
                  CASE WHEN LEFT(@text, LEN(@text) - 10) NOT LIKE '%[^0]%'
                        AND RIGHT(@text, 10) <= '2147483647'
                       THEN CAST (@text AS INT)
                  END
             END
        END
    

    如果你想支持带有任意数量前导零的正负整数:

    SELECT 
             -- Positive integers (or 0):
        CASE WHEN @text NOT LIKE '%[^0-9]%' THEN
             CASE WHEN LEN(@text) BETWEEN 1 AND 9 THEN CAST (@text AS INT)
                  WHEN LEN(@text) >= 10 THEN
                  CASE WHEN LEFT(@text, LEN(@text) - 10) NOT LIKE '%[^0]%'
                        AND RIGHT(@text, 10) <= '2147483647'
                       THEN CAST (@text AS INT)
                  END
             END
             -- Negative integers:
             WHEN LEFT(@text, 1) = '-' THEN
             CASE WHEN RIGHT(@text, LEN(@text) - 1) NOT LIKE '%[^0-9]%' THEN
                  CASE WHEN LEN(@text) BETWEEN 2 AND 10 THEN CAST (@text AS INT)
                       WHEN LEN(@text) >= 11 THEN
                       CASE WHEN SUBSTRING(@text, 2, LEN(@text) - 11) NOT LIKE '%[^0]%'
                             AND RIGHT(@text, 10) <= '2147483648'
                            THEN CAST (@text AS INT)
                       END
                  END
             END
        END
    

    【讨论】:

    • 为了强调一点,短路是not guaranteed,即使是CASE语句。
    • @MichaelGreen:我读过那篇文章;最后一次更新指出:“此代码的所有者 [?] 已将此错误标记为已修复。从他们的 cmets 看来,您应该能够依赖 CASE 语句的表达式评估的确定性顺序。” Microsoft acknowledges 聚合可能会出现该错误,但标量不会出现该错误。
    • 公平点@Douglas。我记得在过去的几个月里,一位知名博主发表了一篇关于 CASE 短路 mot 在编译时可靠在编译时的帖子,即使运行时排序得到尊重。但是,我目前找不到该参考资料。我的动机是警告社区这可能是个问题,具体取决于他们的版本/版本/补丁级别,我以该链接为例,仅此而已。
    • @MichaelGreen:同意;恕我直言,这是/曾经是 SQL Server 的一个严重缺陷,严重限制了它在需要数据验证的场景中的可用性。
    • 为什么不在对话中使用 BIGINT?
    【解决方案5】:

    问候。

    我在 SQL Server 2008 中写了一个有用的标量函数来模拟 SQL SERVER 2012 的 TRY_CAST 函数。

    您可以在下面的下一个链接中看到它,我们互相帮助改进它。 SQL Server 2008 的 TRY_CAST 函数 https://gist.github.com/jotapardo/800881eba8c5072eb8d99ce6eb74c8bb

    两个主要区别是您必须传递 3 个参数,而您 必须另外对该字段执行显式 CONVERT 或 CAST。 但是,它仍然非常有用,因为它允许您返回一个 未正确执行 CAST 时的默认值。

    dbo.TRY_CAST(Expression, Data_Type, ReturnValueIfErrorCast)
    

    示例:

    SELECT   CASE WHEN dbo.TRY_CAST('6666666166666212', 'INT', DEFAULT) IS NULL   
                            THEN 'Cast failed'  
                            ELSE 'Cast succeeded'  
                        END AS Result; 
    

    目前仅支持数据类型INT、DATE、NUMERIC、BIT和FLOAT

    希望对你有用。

    代码:

    DECLARE @strSQL NVARCHAR(1000)
    IF NOT EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[TRY_CAST]'))
        BEGIN
            SET @strSQL = 'CREATE FUNCTION [dbo].[TRY_CAST] () RETURNS INT AS BEGIN RETURN 0 END'
            EXEC sys.sp_executesql @strSQL
        END
    
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    
    /*
    ------------------------------------------------------------------------------------------------------------------------
        Description:    
                        Syntax 
                        ---------------
                        dbo.TRY_CAST(Expression, Data_Type, ReturnValueIfErrorCast)
    
                        +---------------------------+-----------------------+
                        |   Expression              |   VARCHAR(8000)       |
                        +---------------------------+-----------------------+
                        |   Data_Type               |   VARCHAR(8000)       |
                        +---------------------------+-----------------------+
                        |   ReturnValueIfErrorCast  |   SQL_VARIANT = NULL  |
                        +---------------------------+-----------------------+
    
    
                        Arguments
                        ---------------
                        expression
                        The value to be cast. Any valid expression.
    
                        Data_Type
                        The data type into which to cast expression.
    
                        ReturnValueIfErrorCast
                        Value returned if cast fails or is not supported. Required. Set the DEFAULT value by default.
    
    
                        Return Type
                        ----------------
                        Returns value cast to SQL_VARIANT type if the cast succeeds; otherwise, returns null if the parameter @pReturnValueIfErrorCast is set to DEFAULT, 
                        or that the user indicates.
    
    
                        Remarks
                        ----------------
                        dbo.TRY_CAST function simulates the TRY_CAST function reserved of SQL SERVER 2012 for using in SQL SERVER 2008. 
                        dbo.TRY_CAST function takes the value passed to it and tries to convert it to the specified Data_Type. 
                        If the cast succeeds, dbo.TRY_CAST returns the value as SQL_VARIANT type; if the cast doesn´t succees, null is returned if the parameter @pReturnValueIfErrorCast is set to DEFAULT. 
                        If the Data_Type is unsupported will return @pReturnValueIfErrorCast.
                        dbo.TRY_CAST function requires user make an explicit CAST or CONVERT in ANY statements.
                        This version of dbo.TRY_CAST only supports CAST for INT, DATE, NUMERIC and BIT types.
    
    
                        Examples
                        ====================================================================================================
    
                        --A. Test TRY_CAST function returns null
    
                            SELECT   
                                CASE WHEN dbo.TRY_CAST('6666666166666212', 'INT', DEFAULT) IS NULL   
                                THEN 'Cast failed'  
                                ELSE 'Cast succeeded'  
                            END AS Result; 
    
                        GO
    
                        --B. Error Cast With User Value
    
                            SELECT   
                                dbo.TRY_CAST('2147483648', 'INT', DEFAULT) AS [Error Cast With DEFAULT],
                                dbo.TRY_CAST('2147483648', 'INT', -1) AS [Error Cast With User Value],
                                dbo.TRY_CAST('2147483648', 'INT', NULL) AS [Error Cast With User NULL Value]; 
    
                            GO 
    
                        --C. Additional CAST or CONVERT required in any assignment statement
    
                            DECLARE @IntegerVariable AS INT
    
                            SET @IntegerVariable = CAST(dbo.TRY_CAST(123, 'INT', DEFAULT) AS INT)
    
                            SELECT @IntegerVariable
    
                            GO 
    
                            IF OBJECT_ID('tempdb..#temp') IS NOT NULL
                                DROP TABLE #temp
    
                            CREATE TABLE #temp (
                                Id INT IDENTITY
                                , FieldNumeric NUMERIC(3, 1)
                                )
    
                            INSERT INTO dbo.#temp (FieldNumeric)
                            SELECT CAST(dbo.TRY_CAST(12.3, 'NUMERIC(3,1)', 0) AS NUMERIC(3, 1));--Need explicit CAST on INSERT statements
    
                            SELECT *
                            FROM #temp
    
                            DROP TABLE #temp
    
                            GO 
    
                        --D. Supports CAST for INT, DATE, NUMERIC and BIT types.
    
                            SELECT dbo.TRY_CAST(2147483648, 'INT', 0) AS [Cast failed]
                                , dbo.TRY_CAST(2147483647, 'INT', 0) AS [Cast succeeded]
                                , SQL_VARIANT_PROPERTY(dbo.TRY_CAST(212, 'INT', 0), 'BaseType') AS [BaseType];
    
                            SELECT dbo.TRY_CAST('AAAA0101', 'DATE', DEFAULT) AS [Cast failed]
                                , dbo.TRY_CAST('20160101', 'DATE', DEFAULT) AS [Cast succeeded]
                                , SQL_VARIANT_PROPERTY(dbo.TRY_CAST('2016-01-01', 'DATE', DEFAULT), 'BaseType') AS [BaseType];
    
                            SELECT dbo.TRY_CAST(1.23, 'NUMERIC(3,1)', DEFAULT) AS [Cast failed]
                                , dbo.TRY_CAST(12.3, 'NUMERIC(3,1)', DEFAULT) AS [Cast succeeded]
                                , SQL_VARIANT_PROPERTY(dbo.TRY_CAST(12.3, 'NUMERIC(3,1)', DEFAULT), 'BaseType') AS [BaseType];
    
                            SELECT dbo.TRY_CAST('A', 'BIT', DEFAULT) AS [Cast failed]
                                , dbo.TRY_CAST(1, 'BIT', DEFAULT) AS [Cast succeeded]
                                , SQL_VARIANT_PROPERTY(dbo.TRY_CAST('123', 'BIT', DEFAULT), 'BaseType') AS [BaseType];
    
                            GO 
    
                        --E. B. TRY_CAST return NULL on unsupported data_types
    
                            SELECT dbo.TRY_CAST(4, 'xml', DEFAULT) AS [unsupported];  
    
                            GO  
    
                        ====================================================================================================
    
    ------------------------------------------------------------------------------------------------------------------------
        Responsible:    Javier Pardo 
        Date:           diciembre 29/2016
        WB tests:       Javier Pardo 
    ------------------------------------------------------------------------------------------------------------------------
        Update by:      Javier Eduardo Pardo Moreno 
        Date:           febrero 16/2017
        Id update:      JEPM20170216
        Description:    Fix  ISNUMERIC function makes it unreliable. SELECT dbo.TRY_CAST('+', 'INT', 0) will yield Msg 8114, 
                        Level 16, State 5, Line 16 Error converting data type varchar to float.
                        ISNUMERIC() function treats few more characters as numeric, like: – (minus), + (plus), $ (dollar), \ (back slash), (.)dot and (,)comma
                        Collaborator aperiooculus (http://stackoverflow.com/users/3083382/aperiooculus )
    
                        Fix dbo.TRY_CAST('2013/09/20', 'datetime', DEFAULT) for supporting DATETIME format
    
        WB tests:       Javier Pardo 
    
    ------------------------------------------------------------------------------------------------------------------------
    */
    
    ALTER FUNCTION dbo.TRY_CAST
    (
        @pExpression AS VARCHAR(8000),
        @pData_Type AS VARCHAR(8000),
        @pReturnValueIfErrorCast AS SQL_VARIANT = NULL
    )
    RETURNS SQL_VARIANT
    AS
    BEGIN
        --------------------------------------------------------------------------------
        --  INT 
        --------------------------------------------------------------------------------
    
        IF @pData_Type = 'INT'
        BEGIN
            IF ISNUMERIC(@pExpression) = 1 AND @pExpression NOT IN ('-','+','$','.',',','\')    --JEPM20170216
            BEGIN
                DECLARE @pExpressionINT AS FLOAT = CAST(@pExpression AS FLOAT)
    
                IF @pExpressionINT BETWEEN - 2147483648.0 AND 2147483647.0
                BEGIN
                    RETURN CAST(@pExpressionINT as INT)
                END
                ELSE
                BEGIN
                    RETURN @pReturnValueIfErrorCast
                END --FIN IF @pExpressionINT BETWEEN - 2147483648.0 AND 2147483647.0
            END
            ELSE
            BEGIN
                RETURN @pReturnValueIfErrorCast
            END -- FIN IF ISNUMERIC(@pExpression) = 1
        END -- FIN IF @pData_Type = 'INT'
    
        --------------------------------------------------------------------------------
        --  DATE    
        --------------------------------------------------------------------------------
    
        IF @pData_Type IN ('DATE','DATETIME')
        BEGIN
            IF ISDATE(@pExpression) = 1
            BEGIN
    
                DECLARE @pExpressionDATE AS DATETIME = cast(@pExpression AS DATETIME)
    
                IF @pData_Type = 'DATE'
                BEGIN
                    RETURN cast(@pExpressionDATE as DATE)
                END
    
                IF @pData_Type = 'DATETIME'
                BEGIN
                    RETURN cast(@pExpressionDATE as DATETIME)
                END
    
            END
            ELSE 
            BEGIN
    
                DECLARE @pExpressionDATEReplaced AS VARCHAR(50) = REPLACE(REPLACE(REPLACE(@pExpression,'\',''),'/',''),'-','')
    
                IF ISDATE(@pExpressionDATEReplaced) = 1
                BEGIN
                    IF @pData_Type = 'DATE'
                    BEGIN
                        RETURN cast(@pExpressionDATEReplaced as DATE)
                    END
    
                    IF @pData_Type = 'DATETIME'
                    BEGIN
                        RETURN cast(@pExpressionDATEReplaced as DATETIME)
                    END
    
                END
                ELSE
                BEGIN
                    RETURN @pReturnValueIfErrorCast
                END
            END --FIN IF ISDATE(@pExpression) = 1
        END --FIN IF @pData_Type = 'DATE'
    
        --------------------------------------------------------------------------------
        --  NUMERIC 
        --------------------------------------------------------------------------------
    
        IF @pData_Type LIKE 'NUMERIC%'
        BEGIN
    
            IF ISNUMERIC(@pExpression) = 1
            BEGIN
    
                DECLARE @TotalDigitsOfType AS INT = SUBSTRING(@pData_Type,CHARINDEX('(',@pData_Type)+1,  CHARINDEX(',',@pData_Type) - CHARINDEX('(',@pData_Type) - 1)
                    , @TotalDecimalsOfType AS INT = SUBSTRING(@pData_Type,CHARINDEX(',',@pData_Type)+1,  CHARINDEX(')',@pData_Type) - CHARINDEX(',',@pData_Type) - 1)
                    , @TotalDigitsOfValue AS INT 
                    , @TotalDecimalsOfValue AS INT 
                    , @TotalWholeDigitsOfType AS INT 
                    , @TotalWholeDigitsOfValue AS INT 
    
                SET @pExpression = REPLACE(@pExpression, ',','.')
    
                SET @TotalDigitsOfValue = LEN(REPLACE(@pExpression, '.',''))
                SET @TotalDecimalsOfValue = CASE Charindex('.', @pExpression)
                                            WHEN 0
                                                THEN 0
                                            ELSE Len(Cast(Cast(Reverse(CONVERT(VARCHAR(50), @pExpression, 128)) AS FLOAT) AS BIGINT))
                                            END 
                SET @TotalWholeDigitsOfType = @TotalDigitsOfType - @TotalDecimalsOfType
                SET @TotalWholeDigitsOfValue = @TotalDigitsOfValue - @TotalDecimalsOfValue
    
                -- The total digits can not be greater than the p part of NUMERIC (p, s)
                -- The total of decimals can not be greater than the part s of NUMERIC (p, s)
                -- The total digits of the whole part can not be greater than the subtraction between p and s
                IF (@TotalDigitsOfValue <= @TotalDigitsOfType) AND (@TotalDecimalsOfValue <= @TotalDecimalsOfType) AND (@TotalWholeDigitsOfValue <= @TotalWholeDigitsOfType)
                BEGIN
                    DECLARE @pExpressionNUMERIC AS FLOAT
                    SET @pExpressionNUMERIC = CAST (ROUND(@pExpression, @TotalDecimalsOfValue) AS FLOAT) 
    
                    RETURN @pExpressionNUMERIC --Returns type FLOAT
                END 
                else
                BEGIN
                    RETURN @pReturnValueIfErrorCast
                END-- FIN IF (@TotalDigitisOfValue <= @TotalDigits) AND (@TotalDecimalsOfValue <= @TotalDecimals) 
    
            END
            ELSE 
            BEGIN
                RETURN @pReturnValueIfErrorCast
            END --FIN IF ISNUMERIC(@pExpression) = 1
        END --IF @pData_Type LIKE 'NUMERIC%'
    
        --------------------------------------------------------------------------------
        --  BIT 
        --------------------------------------------------------------------------------
    
        IF @pData_Type LIKE 'BIT'
        BEGIN
            IF ISNUMERIC(@pExpression) = 1
            BEGIN
                RETURN CAST(@pExpression AS BIT) 
            END
            ELSE 
            BEGIN
                RETURN @pReturnValueIfErrorCast
            END --FIN IF ISNUMERIC(@pExpression) = 1
        END --IF @pData_Type LIKE 'BIT'
    
    
        --------------------------------------------------------------------------------
        --  FLOAT   
        --------------------------------------------------------------------------------
    
        IF @pData_Type LIKE 'FLOAT'
        BEGIN
            IF ISNUMERIC(REPLACE(REPLACE(@pExpression, CHAR(13), ''), CHAR(10), '')) = 1
            BEGIN
    
                RETURN CAST(@pExpression AS FLOAT) 
            END
            ELSE 
            BEGIN
    
                IF REPLACE(@pExpression, CHAR(13), '') = '' --Only white spaces are replaced, not new lines
                BEGIN
                    RETURN 0
                END
                ELSE 
                BEGIN
                    RETURN @pReturnValueIfErrorCast
                END --IF REPLACE(@pExpression, CHAR(13), '') = '' 
    
            END --FIN IF ISNUMERIC(@pExpression) = 1
        END --IF @pData_Type LIKE 'FLOAT'
    
        --------------------------------------------------------------------------------
        --  Any other unsupported data type will return NULL or the value assigned by the user to @pReturnValueIfErrorCast  
        --------------------------------------------------------------------------------
    
        RETURN @pReturnValueIfErrorCast
    
    
    
    END
    

    【讨论】:

    • 谁能告诉我为什么会有负面反馈?
    • 我不明白他们是如何提出负面意见的,甚至没有提及原因。这样你就学不会了。请反馈
    • 您可能希望在答案中包含实现。
    • @AperioOculus 非常感谢您的反馈。我更新了代码!再次感谢您!
    【解决方案6】:

    Joseph 的回答指出 ISNUMERIC 也可以处理像 '1.3e+3' 这样的科学记数法,但他的回答不处理这种数字格式。

    铸造货币或浮动首先处理货币和科学问题:

    IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[TryConvertInt]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
    DROP FUNCTION [dbo].[TryConvertInt]
    GO
    
    CREATE FUNCTION dbo.TryConvertInt(@Value varchar(18))
    RETURNS bigint
    AS
    BEGIN
        DECLARE @IntValue bigint;
    
        IF (ISNUMERIC(@Value) = 1)
            IF (@Value like '%e%')
                SET @IntValue = CAST(Cast(@Value as float) as bigint);
            ELSE
                SET @IntValue = CAST(CAST(@Value as money) as bigint);
        ELSE
            SET @IntValue = NULL;
    
        RETURN @IntValue;
    END
    

    如果数字大于 bigint,函数将失败。

    如果要返回不同的默认值,请保留此函数,使其具有通用性,然后替换 null:

    SELECT IsNull(dbo.TryConvertInt('nan') , 1000);
    

    【讨论】:

      【解决方案7】:

      我知道它不漂亮,但它很简单。试试这个:

      declare @AlpaNumber nvarchar(50) = 'ABC'
      declare @MyNumber int = 0
      begin Try
      select @MyNumber = case when ISNUMERIC(@AlpaNumber) = 1 then cast(@AlpaNumber as int) else 0 end
      End Try
      Begin Catch
          -- Do nothing
      End Catch 
      
      if exists(select * from mytable where mynumber = @MyNumber)
      Begin
      print 'Found'
      End
      Else
      Begin
       print 'Not Found'
      End
      

      【讨论】:

        【解决方案8】:

        我对这个问题的解决方案是创建如下所示的函数。我的要求包括数字必须是标准整数,而不是 BIGINT,并且我需要允许负数和正数。我还没有发现失败的情况。

        CREATE FUNCTION [dbo].[udfIsInteger]
        (
            -- Add the parameters for the function here
            @Value nvarchar(max)
        )
        RETURNS int
        AS
        BEGIN
            -- Declare the return variable here
            DECLARE @Result int = 0
        
            -- Add the T-SQL statements to compute the return value here
            DECLARE @MinValue nvarchar(11) = '-2147483648'
            DECLARE @MaxValue nvarchar(10) = '2147483647'
        
            SET @Value = ISNULL(@Value,'')
        
            IF LEN(@Value)=0 OR 
              ISNUMERIC(@Value)<>1 OR
              (LEFT(@Value,1)='-' AND LEN(@Value)>11) OR
              (LEFT(@Value,1)='-' AND LEN(@Value)=11 AND @Value>@MinValue) OR
              (LEFT(@Value,1)<>'-' AND LEN(@Value)>10) OR
              (LEFT(@Value,1)<>'-' AND LEN(@Value)=10 AND @Value>@MaxValue)
              GOTO FINISHED
        
            DECLARE @cnt int = 0
            WHILE @cnt<LEN(@Value)
            BEGIN
              SET @cnt=@cnt+1
              IF SUBSTRING(@Value,@cnt,1) NOT IN ('-','0','1','2','3','4','5','6','7','8','9') GOTO FINISHED
            END
            SET @Result=1
        
        FINISHED:
            -- Return the result of the function
            RETURN @Result
        
        END
        

        【讨论】:

          猜你喜欢
          • 2012-05-07
          • 2013-03-10
          • 1970-01-01
          • 2017-06-11
          • 1970-01-01
          • 1970-01-01
          • 2012-11-12
          • 1970-01-01
          • 2020-10-30
          相关资源
          最近更新 更多