533 Stimmen

Wie teile ich einen abgegrenzten String auf, um auf einzelne Elemente zugreifen zu können?

Mit SQL Server, wie kann ich einen String aufteilen, um auf Element x zugreifen zu können?

Nehmen wir einen String "Hallo John Smith". Wie kann ich den String nach Leerzeichen aufteilen und auf das Element an Index 1 zugreifen, das "John" zurückgeben sollte?

3 Stimmen

5 Stimmen

Die höchsten Antworten hier sind - zumindest für mich - ziemlich altmodisch und eher veraltet. Prozedurale Logik, Schleifen, Rekursionen, CLR, Funktionen, viele Codezeilen... Es könnte interessant sein, die "aktiven" Antworten zu lesen, um aktuellere Ansätze zu finden.

0 Stimmen

Ich habe eine neue Antwort mit einem aktuelleren Ansatz hinzugefügt: stackoverflow.com/a/49669994/632604

9voto

josejuan Punkte 8944

Dieses Muster funktioniert gut und du kannst es verallgemeinern

Convert(xml,''+Replace(FIELD,'.','')+'').value('(/n[INDEX])','TYPE')
                          ^^^^^                                   ^^^^^     ^^^^

Beachte FIELD, INDEX und TYPE.

Angenommen, es gibt eine Tabelle mit Identifikatoren wie

sys.message.1234.warning.A45
sys.message.1235.error.O98
....

Dann kannst du schreiben

SELECT Source         = q.value('(/n[1])', 'varchar(10)'),
       RecordType     = q.value('(/n[2])', 'varchar(20)'),
       RecordNumber   = q.value('(/n[3])', 'int'),
       Status         = q.value('(/n[4])', 'varchar(5)')
FROM   (
         SELECT   q = Convert(xml,''+Replace(fieldName,'.','')+'')
         FROM     some_TABLE
       ) Q

und alle Teile aufteilen und umwandeln.

0 Stimmen

Das ist hier die einzige Lösung, die es Ihnen ermöglicht, auf spezifische Typen zu umzustellen, und ist mäßig effizient (CLR ist immer noch am effizientesten, aber dieser Ansatz verarbeitet eine 8-GB-, 10-Token-, 10-Mio.-Zeilen-Tabelle in etwa 9 Minuten (AWS m3-Server, 4k-IOPS-bereitgestellte Festplatte)

9voto

angel Punkte 4194

Ich benutze die Antwort von Frederic, aber das hat in SQL Server 2005 nicht funktioniert

Ich habe es geändert und verwende select mit union all und es funktioniert

DECLARE @str varchar(max)
SET @str = 'Hello John Smith how are you'

DECLARE @separator varchar(max)
SET @separator = ' '

DECLARE @Splited table(id int IDENTITY(1,1), item varchar(max))

SET @str = REPLACE(@str, @separator, ''' UNION ALL SELECT ''')
SET @str = ' SELECT  ''' + @str + '''  ' 

INSERT INTO @Splited
EXEC(@str)

SELECT * FROM @Splited

Und das Ergebnis ist:

id  item
1   Hello
2   John
3   Smith
4   how
5   are
6   you

0 Stimmen

Das ist wirklich das Beste, was ich je im Bereich SQL gesehen habe, es hat für meine Arbeit funktioniert und ich schätze das sehr, danke!

0 Stimmen

Ich war wirklich aufgeregt, als ich das sah, weil es so sauber und einfach zu verstehen aussah, aber leider kann man dies nicht in eine UDF einfügen wegen des EXEC. EXEC ruft implizit eine gespeicherte Prozedur auf, und man kann keine gespeicherten Prozeduren in UDFs verwenden.

0 Stimmen

Das funktioniert perfekt!! Ich habe mich gerade damit beschäftigt, eine Funktion (SplitStrings_Moden) von hier zu verwenden: sqlperformance.com/2012/07/t-sql-queries/split-strings#comme‌​nts , die dies tut, und es hat eineinhalb Minuten gedauert, um die Daten aufzuteilen und die Zeilen zurückzugeben, wenn nur 4 Kontonummern verwendet wurden. Ich habe Ihre Version getestet, mit einem Left Join auf die Tabelle mit den Daten zu Kontonummern, und es hat nur 2 oder 3 Sekunden gedauert! Ein großer Unterschied und es funktioniert einwandfrei! Ich würde dies 20 Stimmen geben, wenn möglich!

8voto

Ramazan Binarbasi Punkte 767

Noch eine Funktion, um den n-ten Teil eines Strings nach einem Trennzeichen zu erhalten:

create function GetStringPartByDelimeter (
    @value as nvarchar(max),
    @delimeter as nvarchar(max),
    @position as int
) returns NVARCHAR(MAX) 
AS BEGIN
    declare @startPos as int
    declare @endPos as int
    set @endPos = -1
    while (@position > 0 and @endPos != 0) begin
        set @startPos = @endPos + 1
        set @endPos = charindex(@delimeter, @value, @startPos)

        if(@position = 1) begin
            if(@endPos = 0)
                set @endPos = len(@value) + 1

            return substring(@value, @startPos, @endPos - @startPos)
        end

        set @position = @position - 1
    end

    return null
end

Und die Verwendung:

select dbo.GetStringPartByDelimeter ('a;b;c;d;e', ';', 3)

das gibt zurück:

c

0 Stimmen

Ich mag diese Lösung als Option, um eine einzelne Teilzeichenfolge zurückzugeben, anstatt eine analysierte Tabelle zu erhalten, aus der Sie dann auswählen müssen. Die Verwendung eines Tabellenergebnisses hat ihre Verwendungszwecke, aber für das, was ich brauchte, hat dies perfekt funktioniert.

7voto

Gorgi Rankovski Punkte 2243

Wenn Ihre Datenbank eine Kompatibilitätsstufe von 130 oder höher hat, können Sie die STRING_SPLIT-Funktion zusammen mit den OFFSET FETCH-Klauseln verwenden, um den spezifischen Eintrag nach Index zu erhalten.

Um das Element am Index N (nullbasiert) zu erhalten, können Sie den folgenden Code verwenden

SELECT value
FROM STRING_SPLIT('Hallo John Smith',' ')
ORDER BY (SELECT NULL)
OFFSET N ROWS
FETCH NEXT 1 ROWS ONLY

Um die Kompatibilitätsstufe Ihrer Datenbank zu überprüfen, führen Sie diesen Code aus:

SELECT compatibility_level  
FROM sys.databases WHERE name = 'IhrDBName';

0 Stimmen

Der Trick liegt in den OFFSET 1 REIHEN, die das erste Element überspringen und das zweite Element zurückgeben wird. Wenn Ihre Indizes auf 0 basieren und @X die Variable ist, die den Index des Elements hält, das Sie abrufen möchten, können Sie sicher OFFSET @X REIHEN setzen.

0 Stimmen

Okay, habe ich vorher nicht verwendet... Schön zu wissen... Ich würde immer noch den xml-split-basierten Ansatz bevorzugen, da er es ermöglicht, den Wert sicher zu holen und keine Unterabfrage benötigt, aber das ist auch gut. +1 von meiner Seite.

3 Stimmen

Das Problem hier ist, dass STRING_SPLIT die Reihenfolge der zurückgegebenen Ergebnisse nicht garantiert. Daher kann dein Element 1 möglicherweise nicht mein Element 1 sein.

6voto

kta Punkte 18216

Ich habe nach der Lösung im Netz gesucht und das unten stehende hat für mich funktioniert. Ref.

Und Sie rufen die Funktion wie folgt auf :

SELECT * FROM dbo.split('ram shyam hari gopal',' ')

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE FUNCTION [dbo].[Split](@String VARCHAR(8000), @Delimiter CHAR(1))       
RETURNS @temptable TABLE (items VARCHAR(8000))       
AS       
BEGIN       
    DECLARE @idx INT       
    DECLARE @slice VARCHAR(8000)        
    SELECT @idx = 1       
    IF len(@String)<1 OR @String IS NULL  RETURN       
    WHILE @idx!= 0       
    BEGIN       
        SET @idx = charindex(@Delimiter,@String)       
        IF @idx!=0       
            SET @slice = LEFT(@String,@idx - 1)       
        ELSE       
            SET @slice = @String       
        IF(len(@slice)>0)  
            INSERT INTO @temptable(Items) VALUES(@slice)       
        SET @String = RIGHT(@String,len(@String) - @idx)       
        IF len(@String) = 0 break       
    END   
    RETURN       
END

0 Stimmen

Sie können nicht einfach auf das N-te Element mit dieser Funktion zugreifen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X