Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

try_parse in SQL Server 2008

Tags:

sql-server

What is the simplest way to get the same output in SQL Server 2008?

SQLServer 2012 :

select
    try_parse(Isnull('123.66',0) as float) as a ,
    try_parse(Isnull('.',0) as float) as b 

Result

a       b
------------
123.66  NULL

SQLServer 2008 : ?

like image 642
Chanaka Avatar asked Jun 12 '15 06:06

Chanaka


People also ask

What is TRY_Parse in SQL?

The TRY_Parse function is used to convert string data into numeric or date data types. It returns NULL if the conversion is not possible.

How to use TRY_ CONVERT in SQL Server 2008?

However, it is still very useful because it allows you to return a default value if CAST is not performed correctly. Your function's dependency on the 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.

What is Try_convert in SQL?

TRY_CONVERT takes the value passed to it and tries to convert it to the specified data_type. If the cast succeeds, TRY_CONVERT returns the value as the specified data_type; if an error occurs, null is returned. However if you request a conversion that is explicitly not permitted, then TRY_CONVERT fails with an error.

Is numeric SQL Server?

What is the SQL Server ISNUMERIC function? As defined in the official Microsoft SQL Server documentation, the ISNUMERIC function determines whether an expression is a valid numeric type. It is a scalar function that takes a string expression as a parameter and returns an integer.


2 Answers

TRY_PARSE does two things - parse text using a specific culture and return NULL if the cast fails. In SQL Server 2008 you can emulate part of this functionality using the ISNUMERIC function, as shown here:

select 
    CASE
        WHEN ISNUMERIC(@input)=1 and LEFT(@input,1) LIKE'[0-9]' THEN 
            CAST(@input as float)  
        ELSE 
            NULL 
    END,

ISNUMERIC will return 1 even for . or '.5' though, causing the cast to fail. This is covered by the second check LEFT(@input,1) LIKE'[0-9]'

You can create a scalar function so you don't have to type all this each time you want to cast a value:

CREATE FUNCTION try_parse_float(@input varchar(20)) 
returns float
AS
begin
    declare @result float;
    select @result=CASE
                       WHEN ISNUMERIC(@input)=1 and LEFT(@input,1) LIKE'[0-9]' 
                           THEN CAST(@input as float)  
                       ELSE NULL 
                    END;
    return @result;
end

So you can write

SELECT dbo.try_parse_float('123,4'), try_parse_float('.')

-----   ----
123.4   NULL

EDIT

The safest and fastest option would be simply to avoid storing numeric values as text in the database, making sure the data is parsed during loading instead. For example, .NET and OLEDB providers can parse "123-" to -123 while T-SQL can't.

It's also much easier to handle custom formats during loading, eg with a float.TryParseExact call before saving form data to the database, or with a C# Script component in an SSIS ETL script.

like image 139
Panagiotis Kanavos Avatar answered Oct 14 '22 13:10

Panagiotis Kanavos


I wrote a useful scalar function to simulate the TRY_CAST function of SQL SERVER 2012 in SQL Server 2008.

dbo.TRY_CAST(Expression, Data_Type, ReturnValueIfErrorCast)

The two main differences with TRY_CAST Function fo SQL Server 2012 are that you must pass 3 parameters and you must additionally perform an explicit CONVERT or CAST to the field. However, it is still very useful because it allows you to return a default value if CAST is not performed correctly.

FUNCTION CODE:

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 
------------------------------------------------------------------------------------------------------------------------
*/

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
        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 = 'DATE'
    BEGIN
        IF ISDATE(@pExpression) = 1
        BEGIN
            DECLARE @pExpressionDATE AS DATE = cast(@pExpression AS DATE)

            RETURN cast(@pExpressionDATE as DATE)
        END
        ELSE 
        BEGIN
            RETURN @pReturnValueIfErrorCast
        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

For now only supports the data types INT, DATE, NUMERIC, BIT and FLOAT. You can find the last versión of this code in the next link below and we help each other to improve it. TRY_CAST Function for SQL Server 2008 https://gist.github.com/jotapardo/800881eba8c5072eb8d99ce6eb74c8bb

like image 44
JotaPardo Avatar answered Oct 14 '22 13:10

JotaPardo