Inline Split mittels CHARINDEX

By Frank Kalis

Posted on Jul 12, 2004 von in SQL Server

Diese Frage ist auch ein Kandidat für die "Häufigste Frage". Dabei kann man sehr häufig die abstrusesten Antworten beobachten. Natürlich kann man dieses Problem mit Hilfe eines Cursors lösen. Stellt sich nur nachher die Frage, wie man das Problem des Cursors los wird.

Vielleicht würde man folgendermassen anfangen:

CREATE TABLE MyNames 
(
MyName VARCHAR(20)
)
DECLARE @s VARCHAR(1000)
DECLARE @i INT
SET @s = 'Frank,,Foo,,,Bar,,'
SET @i = CHARINDEX(',',@s)
WHILE @i>0
BEGIN
IF LEFT(@s,@i-1) <> ''
BEGIN
SET NOCOUNT ON
INSERT INTO MyNames VALUES (LEFT(@s,@i-1))
SET NOCOUNT OFF
END
SET @s = RIGHT(@s,LEN(@s)-@i)
SET @i = CHARINDEX(',',@s)
END
--PRINT @s
SELECT * FROM MyNames
DROP TABLE MyNames

MyName
--------------------
Frank
Foo
Bar

(3 row(s) affected)

Als nächstes möchte man vielleicht die WHILE Schleife eliminieren. Dies kann schnell durch Einsatz einer nummerischen Hilfstabelle erreicht werden.

DECLARE @s varchar(256)
SET @s = 'Frank,,Foo,,,Bar,,'
--INSERT MyNames
SELECT
RIGHT(LEFT(@s,Number-1),CHARINDEX(',',REVERSE(LEFT(','+@s,Number-1))))
FROM master..spt_values
WHERE Type = 'P' AND Number BETWEEN 1 AND LEN(@s)
AND SUBSTRING(@s,Number,1) = ',' AND SUBSTRING(@s,Number-1,1) <> ','

------------------------
Frank
Foo
Bar

(3 row(s) affected)

Danke an Jonathan van Houtte für diesen Vorschlag.
Nun ist spt_values in der master Datenbank eine kleine Hilfstabelle, die vom SQL Server für verschiedene interne Zwecke verwendet wird. Wenn man nicht auf diese nicht dokumentierte Tabelle zurückgreifen will, kann man auch seine eigene Nummerntabelle erstellen, was dann ungefähr folgendermassen aussieht:

SET NOCOUNT ON
SELECT TOP 256 Number = IDENTITY(INT)
INTO MyNumbers
FROM Sysobjects S1
CROSS JOIN Sysobjects S2

DECLARE @s varchar(256)
SET @s = 'Frank,,Foo,,,Bar,,'
SELECT
RIGHT(LEFT(@s,Number-1),CHARINDEX(',',REVERSE(LEFT(','+@s,Number-1))))
FROM MyNumbers
WHERE Number BETWEEN 1 AND LEN(@s)
AND SUBSTRING(@s,Number,1) = ',' AND SUBSTRING(@s,Number-1,1) <> ','
DROP TABLE MyNumbers
SET NOCOUNT OFF

---------
Frank
Foo
Bar

Viele Wege führen nach Rom, aber jetzt hat man eine nette set-basierte Lösung.

Anmerkung 22.02.2005: Falls der String, aus dem man die Daten extrahieren will, nicht wie im obigen Beispiel mit einem Komma endet, muss man das Statement etwas modifizieren:

DECLARE @strComma VARCHAR(1000)
SET @strComma = '10001,10002,10003,10004,10005,10006,10007'

SELECT
CAST(RIGHT(LEFT(@strComma,Number-1)
, CHARINDEX(',',REVERSE(LEFT(','+@strComma,Number-1)))) AS CHAR(30))
FROM
master..spt_values
WHERE
Type = 'P' AND Number BETWEEN 1 AND LEN(@strComma)+1
AND
(SUBSTRING(@strComma,Number,1) = ',' OR SUBSTRING(@strComma,Number,1) = '')

------------------------------
10001
10002
10003
10004
10005
10006
10007

(7 row(s) affected)

Danke an Peter Falz, der mich darauf aufmerksam gemacht hat. Die Änderung zur Verwendung einer eigenen Nummerntabelle überlasse ich dem geneigten Leser.

Dieser Eintrag wurde eingetragen von und ist abgelegt unter SQL Server. Tags: ,

Noch kein Feedback


Formular wird geladen...