it-swarm.com.de

T-SQL-Splitzeichenfolge basierend auf Trennzeichen

Ich habe einige Daten, die ich basierend auf einem eventuell vorhandenen Trennzeichen aufteilen möchte. 

Beispieldaten:

John/Smith
Jane/Doe
Steve
Bob/Johnson

Ich verwende den folgenden Code, um diese Daten in Vornamen und Nachnamen aufzuteilen:

SELECT SUBSTRING(myColumn, 1, CHARINDEX('/', myColumn)-1) AS FirstName,
       SUBSTRING(myColumn, CHARINDEX('/', myColumn) + 1, 1000) AS LastName
FROM   MyTable

Die Ergebnisse möchte ich:

FirstName---LastName
John--------Smith
Jane--------Doe
Steve-------NULL
Bob---------Johnson

Dieser Code funktioniert einwandfrei, solange alle Zeilen den erwarteten Begrenzer haben, aber Fehler ausgegeben werden, wenn eine Zeile nicht funktioniert:

"Invalid length parameter passed to the LEFT or SUBSTRING function."

Wie kann man dies umschreiben, damit es richtig funktioniert?

38
Sesame

Vielleicht hilft dir das.

SELECT SUBSTRING(myColumn, 1, CASE CHARINDEX('/', myColumn)
            WHEN 0
                THEN LEN(myColumn)
            ELSE CHARINDEX('/', myColumn) - 1
            END) AS FirstName
    ,SUBSTRING(myColumn, CASE CHARINDEX('/', myColumn)
            WHEN 0
                THEN LEN(myColumn) + 1
            ELSE CHARINDEX('/', myColumn) + 1
            END, 1000) AS LastName
FROM MyTable
55
sureshhh

Für diejenigen, die nach Antworten für SQL Server 2016+ suchen. Verwenden Sie die integrierte Funktion STRING_SPLIT 

Z.B:

DECLARE @tags NVARCHAR(400) = 'clothing,road,,touring,bike'  

SELECT value  
FROM STRING_SPLIT(@tags, ',')  
WHERE RTRIM(value) <> '';  

Referenz: https://msdn.Microsoft.com/en-nz/library/mt684588.aspx

6
raga
 SELECT CASE 
 WENN CHARINDEX ('/', myColumn, 0) = 0 
 Dann myColumn 
 ELSE LEFT (myColumn, CHARINDEX ('/', myColumn, 0) -1) 
 ENDE AS Vorname 
 ,FALL 
 WENN CHARINDEX ('/', myColumn, 0) = 0 
 DANN ''
 ELSE RIGHT (meine Spalte, CHARINDEX ('/', REVERSE (meine Spalte), 0) -1) 
 END AS LastName 
 FROM MyTable 
5

Versuchen Sie, die Zeilen, die Zeichenfolgen enthalten, mit dem Trennzeichen herauszufiltern, und arbeiten Sie nur mit den folgenden Zeilen:

SELECT SUBSTRING(myColumn, 1, CHARINDEX('/', myColumn)-1) AS FirstName,
       SUBSTRING(myColumn, CHARINDEX('/', myColumn) + 1, 1000) AS LastName
FROM   MyTable
WHERE CHARINDEX('/', myColumn) > 0

Oder

SELECT SUBSTRING(myColumn, 1, CHARINDEX('/', myColumn)-1) AS FirstName,
       SUBSTRING(myColumn, CHARINDEX('/', myColumn) + 1, 1000) AS LastName
FROM   MyTable
WHERE myColumn LIKE '%/%'
4
jpw

Ich wollte nur eine alternative Möglichkeit zum Teilen einer Zeichenfolge mit mehreren Trennzeichen geben, falls Sie eine SQL Server-Version unter 2016 verwenden.

Die allgemeine Idee ist, alle Zeichen in der Zeichenfolge aufzuteilen, die Position der Begrenzer zu bestimmen und Teilzeichenfolgen relativ zu den Begrenzern zu erhalten. Hier ist ein Beispiel:

-- Sample data
DECLARE @testTable TABLE (
    TestString      VARCHAR(50)
)
INSERT INTO @testTable VALUES 
    ('Teststring,1,2,3')
    ,('Test')

DECLARE @delimiter VARCHAR(1) = ','

-- Generate numbers with which we can enumerate
;WITH Numbers AS (
    SELECT 1 AS N

    UNION ALL 

    SELECT N + 1
    FROM Numbers 
    WHERE N < 255
), 
-- Enumerate letters in the string and select only the delimiters
Letters AS (
    SELECT  n.N
            , SUBSTRING(t.TestString, n.N, 1) AS Letter
            , t.TestString 
            , ROW_NUMBER() OVER (   PARTITION BY t.TestString
                                    ORDER BY n.N
                                ) AS Delimiter_Number 
    FROM Numbers n
        INNER JOIN @testTable t
            ON n <= LEN(t.TestString)
    WHERE SUBSTRING(t.TestString, n, 1) = @delimiter 

    UNION 

    -- Include 0th position to "delimit" the start of the string
    SELECT  0
            , NULL
            , t.TestString 
            , 0
    FROM @testTable t 
)
-- Obtain substrings based on delimiter positions
SELECT  t.TestString 
        , ds.Delimiter_Number + 1 AS Position
        , SUBSTRING(t.TestString, ds.N + 1, ISNULL(de.N, LEN(t.TestString) + 1) - ds.N - 1) AS Delimited_Substring 
FROM @testTable t
    LEFT JOIN Letters ds
        ON t.TestString = ds.TestString 
    LEFT JOIN Letters de
        ON t.TestString = de.TestString 
        AND ds.Delimiter_Number + 1 = de.Delimiter_Number  
OPTION (MAXRECURSION 0)
2
Michael Kwon
ALTER FUNCTION [dbo].[split_string](
          @delimited NVARCHAR(MAX),
          @delimiter NVARCHAR(100)
        ) RETURNS @t TABLE (id INT IDENTITY(1,1), val NVARCHAR(MAX))
AS
BEGIN
  DECLARE @xml XML
  SET @xml = N'<t>' + REPLACE(@delimited,@delimiter,'</t><t>') + '</t>'

  INSERT INTO @t(val)
  SELECT  r.value('.','varchar(MAX)') as item
  FROM  @xml.nodes('/t') as records(r)
  RETURN
END
0
Bruno

Die obigen Beispiele funktionieren gut, wenn es nur ein Trennzeichen gibt, aber es eignet sich nicht für mehrere Trennzeichen. Beachten Sie, dass dies nur für SQL Server 2016 und höher funktioniert.

/*Some Sample Data*/
DECLARE @mytable TABLE ([id] VARCHAR(10), [name] VARCHAR(1000));
INSERT INTO @mytable
VALUES ('1','John/Smith'),('2','Jane/Doe'), ('3','Steve'), ('4','Bob/Johnson')


/*Split based on delimeter*/
SELECT P.id, [1] 'FirstName', [2] 'LastName', [3] 'Col3', [4] 'Col4'
FROM(
    SELECT A.id, X1.VALUE, ROW_NUMBER() OVER (PARTITION BY A.id ORDER BY A.id) RN
    FROM @mytable A
    CROSS APPLY STRING_SPLIT(A.name, '/') X1
    ) A
PIVOT (MAX(A.[VALUE]) FOR A.RN IN ([1],[2],[3],[4],[5])) P
0
James Moore