TSQL - String in Ganzzahl umwandeln oder Standardwert zurückgeben

116

Gibt es in T-SQL eine Möglichkeit, ein nvarchar in int umzuwandeln und einen Standardwert oder NULL zurückzugeben, wenn die Konvertierung fehlschlägt?

Oliver Hanappi
quelle

Antworten:

66

Wenn Sie mit SQL Server 2012 (oder neuer) arbeiten:

Verwenden Sie die Funktion TRY_CONVERT .

Wenn Sie mit SQL Server 2005, 2008 oder 2008 R2 arbeiten:

Erstellen Sie eine benutzerdefinierte Funktion. Dadurch werden die Probleme vermieden , die Fedor Hajdu in Bezug auf Währung, Bruchzahlen usw. erwähnt hat:

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

Referenz: Ich habe diese Seite beim Erstellen meiner Lösung ausgiebig verwendet.

Joseph Sturtevant
quelle
1
Hat jemand das zum Laufen gebracht? Ich habe eine Funktion wie vorgeschlagen erstellt und finde, dass sie mit der vorgeschlagenen Testfunktion Konvertierungsfehler auslöst. Ich stelle mir vor, ich vermisse hier etwas ...
Keith Hoffman
1
@ JosephSturtevant das ist schön
StelioK
Ja, gute Arbeit ... Ich habe viel Arbeit gespart ... Ich bin aufgrund des Kunden nicht auf 2012 oder höher ... Gib mir aber keine Anerkennung :) Ich war nur gut darin, nach der Antwort zu suchen, die funktioniert hat Ich ... Obwohl ich es von Null auf Null geändert habe, da der blöde Varchar eine int-Spalte mit dem Standardwert Null sein sollte :)
CA Martin
134

Ja :). Versuche dies:

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()hat ein paar Probleme von Fedor Hajdu .

Es gibt true für Zeichenfolgen wie $(ist Währung) ,oder .(beide sind Trennzeichen) +und zurück -.

Grzegorz Gierlik
quelle
3
Danke für deine Antwort. Ich hoffte, dass es etwas eleganteres gibt.
Oliver Hanappi
4
Was ist, wenn der Textwert numerisch ist, aber eine Zahl enthält, die größer ist, als eine int-Spalte speichern kann?
Tom Mayfield
8
-1: Leider gibt es zu viele Probleme, als ISNUMERICdass diese Antwort für nicht validierte Daten von Nutzen wäre (und Sie würden die ISNUMERICPrüfung für ordnungsgemäß validierte Daten gar nicht erst benötigen ). Der Autor erkennt die Existenz dieser Probleme an, geht jedoch nicht auf sie ein.
Douglas
7
Wie Joseph erwähnt , sollten Benutzer von SQL 2012+ TRY_CONVERT/ verwenden TRY_CAST, die ausdrücklich dazu bestimmt sind, die Frage des OP zu lösen. Diese Antwort wurde geschrieben, bevor SQL 2012 veröffentlicht wurde.
Brian
3
Ich stimme ab, weil ISNUMERIC ('1,1,1,1,1') = 1 ist und dies niemals zu int.
Mischka
14

Ich würde lieber eine Funktion wie TryParse erstellen oder T-SQL verwenden TRY-CATCH Block verwenden, um das zu erhalten, was Sie wollten.

ISNUMERIC funktioniert nicht immer wie vorgesehen. Der zuvor angegebene Code schlägt fehl, wenn Sie Folgendes tun:

SET @text = '$'

$ sign kann in einen Money-Datentyp konvertiert werden, ISNUMERIC()gibt also in diesem Fall true zurück. Das Gleiche gilt für '-' (Minus), ',' (Komma) und '.' Zeichen.

Fedor Hajdu
quelle
3
. Wahr :( ISNUMERIC()kehrt 1auch für ,und ..
Grzegorz Gierlik
3
... außer Sie können TRY-CATCH nicht in einer Funktion verwenden (zumindest nicht in meiner SQL 2005-Datenbank) ... link
Etherman
12

Wie bereits erwähnt, können bei der Verwendung mehrere Probleme auftreten 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

Wenn Sie eine zuverlässige Konvertierung wünschen, müssen Sie selbst eine codieren.

Update : Meine neue Empfehlung wäre, eine Zwischentestkonvertierung zu verwenden FLOAT, um die Nummer zu validieren. Dieser Ansatz basiert auf dem Kommentar von adrianm . Die Logik kann als Inline-Tabellenwertfunktion definiert werden:

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]
)

Einige Tests:

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]

Die Ergebnisse ähneln der Antwort von Joseph Sturtevant mit den folgenden Hauptunterschieden:

  • Meine Logik toleriert keine Vorkommen von .oder ,um das Verhalten nativer INTConversions nachzuahmen . '1,234'und '1234.0'zurück NULL.
  • Da keine lokalen Variablen verwendet werden, kann meine Funktion als Inline-Tabellenwertfunktion definiert werden, um eine bessere Abfrageoptimierung zu ermöglichen.
  • Josephs Antwort kann aufgrund stiller Kürzungen des Arguments zu falschen Ergebnissen führen. '00000000000000001234'bewertet zu 12. Das Erhöhen der Parameterlänge würde zu Fehlern bei überlaufenden Nummern führen BIGINT, wie z. B. BBANs (Basis-Bankkontonummern) wie '212110090000000235698741'.

Zurückgezogen : Der folgende Ansatz wird nicht mehr empfohlen, da er nur als Referenz dient.

Das folgende Snippet funktioniert mit nicht negativen Ganzzahlen. Es wird überprüft, ob Ihre Zeichenfolge keine nichtstelligen Zeichen enthält, nicht leer ist und nicht überläuft (indem der Maximalwert für den intTyp überschritten wird ). Es gibt jedoch auch NULLgültige Ganzzahlen an, deren Länge aufgrund führender Nullen 10 Zeichen überschreitet.

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 

Wenn Sie eine beliebige Anzahl führender Nullen unterstützen möchten, verwenden Sie die folgenden Schritte. Die verschachtelten CASEAnweisungen sind zwar unhandlich, müssen jedoch die Kurzschlussbewertung fördern und die Wahrscheinlichkeit von Fehlern verringern (z. B. durch Übergabe einer negativen Länge an 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

Wenn Sie positive und negative Ganzzahlen mit einer beliebigen Anzahl führender Nullen unterstützen möchten :

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
Douglas
quelle
3
Um den Punkt zu betonen, ist ein Kurzschluss selbst mit der CASE-Anweisung nicht garantiert .
Michael Green
1
@ MichaelGreen: Ich habe diesen Artikel gelesen. In der letzten Aktualisierung heißt es: "Die Eigentümer dieses Codes [?] haben diesen Fehler als behoben markiert. Aus ihren Kommentaren geht hervor, dass Sie sich bei CASE-Anweisungen auf die deterministische Reihenfolge der Ausdrucksbewertung verlassen können sollten." Microsoft erkennt an, dass der Fehler möglicherweise bei Aggregaten auftritt, nicht jedoch bei Skalaren.
Douglas
1
Fairer Punkt @Douglas. Ich erinnere mich, dass ich in den letzten Monaten einen Beitrag eines der Markenblogger über CASE Short Circuiting gelesen habe, der zur Kompilierungszeit zuverlässig war , selbst wenn die Laufzeitsequenzierung eingehalten wurde. Ich kann diese Referenz derzeit jedoch nicht finden. Meine Motivation die Gemeinschaft zu warnen , war , dass dies kann ein Problem sein, je nach ihrer Version / Ausgabe / Patch - Level und ich diesen Link als Examplar, das ist alles.
Michael Green
1
@ MichaelGreen: Einverstanden; Meiner Meinung nach ist / war dies ein schwerwiegender Mangel in SQL Server, der die Verwendbarkeit für Szenarien, die eine Datenvalidierung erfordern, stark einschränkt.
Douglas
1
Warum verwenden Sie BIGINT nicht mitten im Gespräch?
Alex
2

Grüße.

Ich habe eine nützliche Skalarfunktion geschrieben, um die TRY_CAST-Funktion von SQL SERVER 2012 in SQL Server 2008 zu simulieren.

Sie können es im nächsten Link unten sehen und wir helfen uns gegenseitig, es zu verbessern. TRY_CAST-Funktion für SQL Server 2008 https://gist.github.com/jotapardo/800881eba8c5072eb8d99ce6eb74c8bb

Die beiden Hauptunterschiede bestehen darin, dass Sie 3 Parameter übergeben und zusätzlich eine explizite CONVERT oder CAST für das Feld ausführen müssen. Es ist jedoch immer noch sehr nützlich, da Sie damit einen Standardwert zurückgeben können, wenn CAST nicht korrekt ausgeführt wird.

dbo.TRY_CAST(Expression, Data_Type, ReturnValueIfErrorCast)

Beispiel:

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

Unterstützt derzeit nur die Datentypen INT, DATE, NUMERIC, BIT und FLOAT

Ich hoffe, Sie finden es nützlich.

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 
------------------------------------------------------------------------------------------------------------------------
    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
JotaPardo
quelle
1
Kann mir jemand sagen warum das negative Feedback?
JotaPardo
1
Ich verstehe nicht, wie sie negative Punkte setzen und habe nicht einmal den Grund erwähnt. Auf diese Weise kann man nicht lernen. Bitte
Feedback
2
Möglicherweise möchten Sie die Implementierung in Ihre Antwort aufnehmen.
AperioOculus
1
@AperioOculus vielen Dank für Ihr Feedback. Ich habe den Code aktualisiert! Danke nochmal!
JotaPardo
1

Josephs Antwort wies darauf hin, dass ISNUMERIC auch wissenschaftliche Notationen wie '1.3e + 3' behandelt, aber seine Antwort behandelt dieses Zahlenformat nicht.

Das Casting auf ein Geld oder einen Float behandelt zunächst sowohl die Währung als auch wissenschaftliche Fragen:

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

Die Funktion schlägt fehl, wenn die Zahl größer als ein Bigint ist.

Wenn Sie einen anderen Standardwert zurückgeben möchten, lassen Sie diese Funktion generisch und ersetzen Sie anschließend die Null:

SELECT IsNull(dbo.TryConvertInt('nan') , 1000);
Stephen Turner
quelle
1

Ich weiß, dass es nicht schön ist, aber es ist einfach. Versuche dies:

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
Ramblen Man
quelle
1

Meine Lösung für dieses Problem bestand darin, die unten gezeigte Funktion zu erstellen. Zu meinen Anforderungen gehörte, dass die Zahl eine Standard-Ganzzahl und keine BIGINT sein musste und ich negative und positive Zahlen zulassen musste. Ich habe keinen Umstand gefunden, in dem dies fehlschlägt.

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
Brian Payne
quelle