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

39voto

nathan_jr Punkte 8727

Sie können eine Number-Tabelle nutzen, um das Zeichenparsen durchzuführen.

Erstellen Sie eine physische Zahlen-Tabelle:

    create table dbo.Numbers (N int primary key);
    insert into dbo.Numbers
        select top 1000 row_number() over(order by number) from master..spt_values
    go

Erstellen Sie eine Testtabelle mit 1000000 Zeilen

    create table #yak (i int identity(1,1) primary key, array varchar(50))

    insert into #yak(array)
        select 'a,b,c' from dbo.Numbers n cross join dbo.Numbers nn
    go

Erstellen Sie die Funktion

    create function [dbo].[ufn_ParseArray]
        (   @Input      nvarchar(4000), 
            @Delimiter  char(1) = ',',
            @BaseIdent  int
        )
    returns table as
    return  
        (   select  row_number() over (order by n asc) + (@BaseIdent - 1) [i],
                    substring(@Input, n, charindex(@Delimiter, @Input + @Delimiter, n) - n) s
            from    dbo.Numbers
            where   n <= convert(int, len(@Input)) and
                    substring(@Delimiter + @Input, n, 1) = @Delimiter
        )
    go

Verwendung (gibt 3 Millionen Zeilen in 40 Sekunden auf meinem Laptop aus)

    select * 
    from #yak 
    cross apply dbo.ufn_ParseArray(array, ',', 1)

Bereinigung

    drop table dbo.Numbers;
    drop function  [dbo].[ufn_ParseArray]

Die Leistung hier ist nicht beeindruckend, aber das Aufrufen einer Funktion über einer Million Zeilen in einer Tabelle ist keine gute Idee. Wenn Sie ein Zeichenaufteilen über viele Zeilen durchführen müssen, würde ich die Funktion vermeiden.

2 Stimmen

Die beste Lösung IMO, die anderen haben irgendwelche Einschränkungen.. das ist schnell und kann lange Zeichenfolgen mit vielen Elementen analysieren.

0 Stimmen

Warum bestellst du n absteigend? Wenn es drei Elemente gäbe und wir bei 1 mit der Nummerierung begonnen haben, dann wird das erste Element die Nummer 3 und das letzte die Nummer 1 sein. Würde es nicht intuitivere Ergebnisse liefern, wenn das desc entfernt würde?

1 Stimmen

Vereinbart, wäre in aufsteigender Richtung intuitiver. Ich folgte der Konvention von parsename(), die desc verwendet.

23voto

brendan Punkte 28331

Hier ist eine UDF, die es tun wird. Es wird eine Tabelle der abgegrenzten Werte zurückgeben, habe noch nicht alle Szenarien ausprobiert, aber Ihr Beispiel funktioniert gut.

CREATE FUNCTION SplitString 
(
    -- Fügen Sie die Parameter für die Funktion hier hinzu
    @myString varchar(500),
    @deliminator varchar(10)
)
RETURNS 
@ReturnTable TABELLE 
(
    -- Fügen Sie die Spaltendefinitionen für die TABELLE Variable hier hinzu
    [id] [int] IDENTITY(1,1) NOT NULL,
    [part] [varchar](50) NULL
)
ALS
BEGIN
        Deklarieren Sie @iSpaces int
        Deklarieren Sie @part varchar(50)

        --Leerzeichen initialisieren
        Wählen Sie @iSpaces = charindex(@deliminator,@myString,0)
        während @iSpaces > 0

        Beginnen
            Wählen Sie @part = Teilzeichenfolge(@myString,0,charindex(@deliminator,@myString,0))

            Einfügen In @ReturnTable(part)
            Wählen Sie @part

    Wählen Sie @myString = Teilzeichenfolge(@mystring,charindex(@deliminator,@myString,0)+ len(@deliminator),len(@myString) - charindex(' ',@myString,0))

            Wählen Sie @iSpaces = charindex(@deliminator,@myString,0)
        end

        Wenn len(@myString) > 0
            Einfügen In @ReturnTable
            Wählen Sie @myString

    RETURN 
END
GEHEN

Sie würden ihn so aufrufen:

Wählen Sie * Aus SplitString('Hallo John Smith',' ')

Bearbeitung: Lösung aktualisiert, um Delimiter mit einer Länge>1 zu verarbeiten, wie z.B. :

wählen Sie * Aus SplitString('Hallo**John**Smith','**')

0 Stimmen

Funktioniert nicht für select * from dbo.ethos_SplitString_fn('guy,wicks,war hier',',') id part ----------- -------------------------------------------------- 1 guy 2 wick

2 Stimmen

Pass auf mit len(), da es keine korrekte Anzahl zurückgibt, wenn das Argument am Ende Leerzeichen hat., z.B. len(' - ') = 2.

0 Stimmen

Funktioniert nicht bei: select * from dbo.SplitString('foo,foo test,,,,foo',',')

16voto

Hier poste ich einen einfachen Lösungsweg

CREATE FUNCTION [dbo].[split](
          @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'' + REPLACE(@delimited,@delimiter,'') + ''

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

Führen Sie die Funktion wie folgt aus

  select * from dbo.split('Hello John Smith',' ')

0 Stimmen

Ich mochte diese Lösung. Erweitert es, um einen Skalarwert basierend auf der angegebenen Spalte innerhalb der Ergebnisse zurückzugeben.

0 Stimmen

Ich wurde mit einem '&' im String verbrannt, der mit diesem geteilt werden sollte

10voto

Frederic Punkte 998

Was ist mit der Verwendung der string und der values() Anweisung?

DECLARE @str varchar(max)
SET @str = 'Hallo John Smith'

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

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

SET @str = REPLACE(@str, @separator, '''),(''')
SET @str = 'SELECT * FROM (VALUES(''' + @str + ''')) AS V(A)' 

INSERT INTO @Splited
EXEC(@str)

SELECT * FROM @Splited

Ergebnis erzielt.

id  item
1   Hallo
2   John
3   Smith

1 Stimmen

Ich habe deine Antwort benutzt, aber es hat nicht funktioniert, aber ich habe es geändert und es hat mit Union All funktioniert. Ich benutze SQL 2005.

10voto

Damon Drake Punkte 819

In meiner Meinung nach macht ihr es viel zu kompliziert. Erstellt einfach eine CLR UDF und seid damit fertig.

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Collections.Generic;

public partial class UserDefinedFunctions {
  [SqlFunction]
  public static SqlString SearchString(string Search) {
    List SearchWords = new List();
    foreach (string s in Search.Split(new char[] { ' ' })) {
      if (!s.ToLower().Equals("or") && !s.ToLower().Equals("and")) {
        SearchWords.Add(s);
      }
    }

    return new SqlString(string.Join(" OR ", SearchWords.ToArray()));
  }
};

20 Stimmen

Ich denke, das ist zu kompliziert, weil ich Visual Studio haben muss, dann CLR auf dem Server aktivieren muss, dann das Projekt erstellen und kompilieren muss und schließlich die Assemblys zur Datenbank hinzufügen muss, um sie zu verwenden. Aber es ist immer noch eine interessante Antwort.

3 Stimmen

@guillegr123, es muss nicht kompliziert sein. Du kannst einfach SQL# herunterladen und installieren (kostenlos!), was eine Bibliothek von SQLCLR Funktionen und Prozeduren ist. Du kannst es hier herunterladen SQLsharp.com. Ja, ich bin der Autor, aber String_Split ist in der kostenlosen Version enthalten.

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