2015-06-12 44 views
3

在SQL Server 2008中獲取相同輸出的最簡單方法是什麼?SQL Server 2008中的try_parse

的SQLServer 2012:

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

結果

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

的SQLServer 2008: ?

+1

您必須編寫一個UDF複製在SQL Server 2008 try_parse的行爲,因爲這個功能在SQL Server中添加了2012版 –

+1

如果有一個簡單的方法來達到同樣的在2008年,他們不會將它添加到2012年。 –

+0

您可以嘗試使用'ISNUMERIC'來檢查在投射前數據是否爲數字,如[此處顯示](http://stackoverflow.com/questions/2000045/tsql- (@text AS INT)ELSE NULL END' –

回答

-1

您可以使用此codesnippet應該做你在尋找的東西。 將它添加到更大表格上的選擇應該不是什麼大問題。只需將該變量替換爲代碼列即可。

這裏是例子:

DECLARE @string nvarchar(255) 
SET @string = 'Hali€hHalo' 

SELECT Substring(
      @string, 
      PATINDEX('%[0-9.]%',@string), 
      PATINDEX('%[^0-9.]%', 
       Substring(
         @string, 
         PATINDEX(
          '%[0-9.]%', 
          @string 
        ), 
         LEN(@string) 
       ) 
     )-1 
    ) 
GO 

結果:空字符串,但可以用一個情況下,如果需要一個NULL被更換時... IS NULL ELSE THEN NULL ... END。

的與數字的變量同樣的事情。

DECLARE @string nvarchar(255) 
SET @string = 'Hali123.10€hHalo' 

SELECT Substring(
      @string, 
      PATINDEX('%[0-9.]%',@string), 
      PATINDEX('%[^0-9.]%', 
       Substring(
         @string, 
         PATINDEX(
          '%[0-9.]%', 
          @string 
        ), 
         LEN(@string) 
       ) 
     )-1 
    ) 
GO 

結果:123.10

最好的問候, 離子

+0

我可以得到一個答案,爲什麼你downvote解決方案? – Ionic

+0

'TRY_PARSE'不僅僅是一種舒適功能,這可以通過複製部分功能所需的複雜代碼引起的*不適感來證明。如果有一千個分隔符會怎樣?如果例如小數點分隔符是逗號,如在許多歐洲國家那樣呢?它可能會更簡單/更安全(但更慢)嘗試'cast'並捕獲失敗,例如在標量函數中,而不是嘗試複製'TRY_PARSE'的行爲。只有CLR UDF實際上可以在SQL Server 2008中提供相同的功能 –

+0

那麼如果你有SQL Server 2008而不是SQL Server 2012,那麼試試你的TRY_PARSE。但它不會工作。有些公司將無法升級到SQL Server 2012,因爲許可證模式非常差。這樣你就不能使用try_parse並且需要一個解決方法 - 就像提問者那樣。可能很容易檢查分隔符並適應。您也可以在無法轉換的行上使用此語句。 – Ionic

4

TRY_PARSE做兩件事情 - 用特定的文化解析文本如果轉換失敗則返回NULL。在SQL Server 2008中您可以使用ISNUMERIC功能,如shown here效仿這一部分功能:

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

ISNUMERIC返回1甚至.或」 0.5' ,雖然,造成投失敗。這是通過第二次檢查覆蓋LEFT(@input,1) LIKE'[0-9]'

您可以創建一個標量函數,所以你沒有這一切要投射的值每次都輸入:

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 

所以,你可以寫

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

----- ---- 
123.4 NULL 

編輯

最安全,最快捷的選擇是簡單地避免存儲數字VA在數據庫中作爲文本提示,確保在加載過程中解析數據。例如,.NET和OLEDB提供程序可以解析"123-"-123,而T-SQL不能。

在加載過程中處理自定義格式(例如,在將表單數據保存到數據庫之前調用float.TryParseExact或在SSIS ETL腳本中使用C#腳本組件),處理自定義格式也容易得多。

1

我寫了一個有用的標量函數來模擬SQL SERVER 2012的TRY_CAST功能在SQL Server 2008中。

dbo.TRY_CAST(Expression, Data_Type, ReturnValueIfErrorCast) 

兩個與TRY_CAST功能FO SQL Server 2012的主要區別是,你必須通過3個參數,你 必須另外進行明確的轉換或轉換成字段。 但是,它仍然非常有用,因爲如果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。你可以在下面的鏈接中找到這段代碼的最後一個版本,我們互相幫助改進它。 TRY_CAST功能的SQL Server 2008https://gist.github.com/jotapardo/800881eba8c5072eb8d99ce6eb74c8bb