繁体   English   中英

SQL Server 2008 R2 Express中的try_convert

[英]try_convert in SQL Server 2008 R2 Express

我有一个为SQL Server 2012写的查询,并使用try_convert()函数。 现在,我需要在SQL Server 2008 R2 Express上执行查询,据我了解, try_convert()在2008 R2中不受支持。

我当前的查询包含以下块:

CASE WHEN (try_convert(decimal, tew_userdata_locTo.use_data0) IS NULL) 
THEN .. ELSE .. END

这给了我一个正确或错误的结果,让我知道我是否可以将特定的值转换为小数。 如果我可以转换值,则可以。 如果没有,我将使用默认的十进制值并继续使用该值。

关于我可以写的内容的任何想法都可以在SQL Server 2008 R2中使用吗?

try_convert()尝试进行转换。 这是处理转换错误的好方法(或者至少比以前的SQL Server更好,这没什么)。 您可以使用like来查看字符串“看起来”是否像有效的十进制。 这是一种尝试:

CASE WHEN tew_userdata_locTo.use_data0 not like '%[^0-9.]%' and
          tew_userdata_locTo.use_data0 not like '%.%.%'
     THEN convert(decimal, tew_userdata_locTo.use_data0)
THEN .. ELSE .. END

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

dbo.TRY_CAST(Expression, Data_Type, ReturnValueIfErrorCast)

SQL Server 2012的TRY_CAST函数的两个主要区别在于,您必须传递3个参数,并且还必须对该字段执行显式的CONVERT或CAST。 但是,它仍然非常有用,因为如果未正确执行CAST,它允许您返回默认值。

功能码:

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

目前仅支持INT,DATE,NUMERIC,BIT和FLOAT数据类型。 您可以在下面的下一个链接中找到此代码的最新版本,我们会互相帮助进行改进。 SQL Server 2008的TRY_CAST函数 https://gist.github.com/jotapardo/800881eba8c5072eb8d99ce6eb74c8bb

另一种解决方案是使用CLR程序集。 这允许“链接”用C#或VB编写的函数,这些函数的运行速度比任何SQL等效函数都快得多。

下面的文章介绍了如何在Visual Studio的专业版本中创建CLR程序集。 但是,可以通过任何其他版本(即社区)将其创建为类库,并在数据库程序集中手动注册。

对于当前问题,只需使用以下类即可完成检查:

[Microsoft.SqlServer.Server.SqlFunction]
public static SqlBoolean IsDecimal(string value)
{
    decimal decValue;
    bool isNumeric = decimal.TryParse(value, out decValue);
    return new SqlBoolean(isNumeric);
}

用法示例:

select dbo.IsDecimal(1.0) --> 1
select dbo.IsDecimal(1.0a) --> 0

-- quick and dirty performance test -> takes about 2 seconds (250K records)
-- as opposed to about 1 second of just selecting the data without any filter 
select * from sys.messages where dbo.IsDecimal(severity) = 1

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM