2011-02-07 78 views
16

有沒有辦法調用Sql Server函數轉換/拋出而不讓它們拋出異常?將varchar值轉換爲int,而不會在輸入錯誤時拋出異常

基本上,我有一列包含字母數字數據,我從字段中提取值,我想將數據顯示爲整數值。有時候提取的數據不是數字,在這種情況下,我希望Sql Server跳過該行(返回null或0)。

眼下SQL SELECT語句失敗,出現「轉換爲nvarchar值時,轉換失敗‘爲XXXXX’爲int數據類型。

我想要的是類似於C#的int.TryParse東西。

建議?

+1

這就是爲什麼你正確的數據類型。 – 2011-02-07 17:21:18

回答

23
select case when isnumeric(YourColumn + '.0e0') = 1 
      then cast(YourColumn as int) 
      else NULL 
     end /* case */ 
    from YourTable 
+3

我認爲值得在解決方案中解釋神奇的'.0e0':它確保值是一個整數。 `IsNumeric('1.5')`和`IsNumeric('1e5')`都返回true,但會失敗轉換爲int。 `IsNumeric('1.5.0e0')`和`IsNumeric('1e5.0e0')`都會返回假 – Kip 2013-05-16 13:23:08

+0

這是一個好方法,但如果列只包含`-`,則仍然會出錯。同時檢查INT的最小/最大範圍。 – Styxxy 2014-04-01 09:38:30

1

檢查,以確保它是一個整數,你在那裏使用下面的函數

/****** Object: UserDefinedFunction [dbo].[IsInteger] Script Date: 04/10/2013 09:46:19 ******/ 
SET ANSI_NULLS ON 
GO 

SET QUOTED_IDENTIFIER ON 
GO 

CREATE Function [dbo].[IsInteger](@Value VarChar(50)) 
Returns Bit 
As 
Begin 

DECLARE @is_int bit 
SELECT @is_int = CASE 
    WHEN @Value IS NULL THEN 0 
    WHEN @Value = ' ' THEN 0 
    WHEN ISNUMERIC(@Value + '.0e0') = 0  THEN 0 
    WHEN @Value LIKE '%\[^-+ 0-9\]%' THEN 0 
    WHEN CAST(@Value AS NUMERIC(38, 0)) 
     NOT BETWEEN -2147483648. AND 2147483647. THEN 0 
    ELSE 1 
    END 

return @is_int 

End 
GO 

然後做鑄造前where子句中dbo.IsInteger(yourstring)

1

這種嘗試我創建的功能

官方鏈接: https://gist.github.com/jotapardo/800881eba8c5072eb8d99ce6eb74c8bb

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 

而且試試這個:

SELECT dbo.TRY_CAST(YourColumn, 'INT', NULL) 

目前只支持數據類型INT,DATE,數字,BIT和浮

我希望你覺得它有用。

相關問題