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?
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
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
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
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 '%/%'
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)
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
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