Wie teile ich unter Verwendung von SQL Server eine Zeichenfolge, damit ich auf Element x zugreifen kann?
Nehmen Sie eine Zeichenfolge "Hallo John Smith". Wie kann ich die Zeichenfolge nach Leerzeichen aufteilen und auf das Element in Index 1 zugreifen, das "John" zurückgeben soll?
sql
sql-server
tsql
split
GateKiller
quelle
quelle
Antworten:
Möglicherweise finden Sie die Lösung in SQL User Defined Function zum Parsen einer durch Trennzeichen getrennten Zeichenfolge hilfreich (aus The Code Project ).
Sie können diese einfache Logik verwenden:
quelle
SET @p_SourceText = RTRIM( LTRIM( @p_SourceText)) SET @w_Length = DATALENGTH( RTRIM( LTRIM( @p_SourceText)))
nichtSET @p_SourceText = RTRIM( LTRIM( @p_SourceText)) SET @w_Length = DATALENGTH( @p_SourceText)
?STRING_SPLIT
, die eine Zeichenfolge aufteilt und ein einspaltiges Tabellenergebnis zurückgibt, das Sie in einerSELECT
Anweisung oder an anderer Stelle verwenden können.Ich glaube nicht, dass SQL Server über eine integrierte Split-Funktion verfügt. Abgesehen von einer UDF ist die einzige andere Antwort, die ich kenne, die Entführung der PARSENAME-Funktion:
PARSENAME nimmt eine Zeichenfolge und teilt sie in das Punktzeichen auf. Als zweites Argument wird eine Zahl verwendet, und diese Zahl gibt an, welches Segment der Zeichenfolge zurückgegeben werden soll (von hinten nach vorne).
Offensichtliches Problem ist, wenn die Zeichenfolge bereits einen Punkt enthält. Ich denke immer noch, dass die Verwendung eines UDF der beste Weg ist ... irgendwelche anderen Vorschläge?
quelle
SPLIT()
Funktion wird nicht bereitgestellt, da sie ein schlechtes Datenbankdesign fördert und die Datenbank niemals für die Verwendung von Daten optimiert wird, die in diesem Format gespeichert sind. Das RDBMS ist nicht verpflichtet, Entwicklern dabei zu helfen, dumme Dinge zu tun, für die es entwickelt wurde, um es nicht zu handhaben. Die richtige Antwort lautet immer "Normalisieren Sie Ihre Datenbank so, wie wir es Ihnen vor 40 Jahren gesagt haben." Weder SQL noch das RDBMS sind für schlechtes Design verantwortlich.Erstellen Sie zunächst eine Funktion (mit CTE macht der allgemeine Tabellenausdruck die Notwendigkeit einer temporären Tabelle überflüssig).
Verwenden Sie es dann wie eine beliebige Tabelle (oder ändern Sie es so, dass es in Ihren vorhandenen gespeicherten Prozess passt).
Aktualisieren
Die vorherige Version schlug für Eingabezeichenfolgen mit mehr als 4000 Zeichen fehl. Diese Version kümmert sich um die Einschränkung:
Die Nutzung bleibt gleich.
quelle
100
(um eine Endlosschleife zu verhindern). Verwenden Sie den MAXRECURSION-Hinweis , um die Anzahl der Rekursionsstufen zu definieren (0
to32767
,0
ist "no limit" - kann den Server beschädigen ). Übrigens, viel bessere Antwort alsPARSENAME
, weil es universell ist :-). +1maxrecursion
beim Hinzufügen zu dieser Lösung diese Frage und ihre Antworten. So richten Sie diemaxrecursion
Option für einen CTE in einer Tabellenwertfunktion ein .s
nicht mehr definiert sindDie meisten der hier verwendeten Lösungen verwenden while-Schleifen oder rekursive CTEs. Ich verspreche, dass ein satzbasierter Ansatz überlegen ist, wenn Sie ein anderes Trennzeichen als ein Leerzeichen verwenden können:
Beispielnutzung:
Ergebnisse:
Sie können das
idx
gewünschte Element auch als Argument zur Funktion hinzufügen , aber das überlasse ich dem Leser als Übung.Sie können dies nicht tun , mit nur der nativen
STRING_SPLIT
Funktion hinzugefügt in SQL Server 2016, weil es keine Garantie dafür gibt , dass die Ausgabe in der Reihenfolge der Originalliste wiedergegeben wird. Mit anderen Worten, wenn Sie3,6,1
das Ergebnis übergeben, wird es wahrscheinlich in dieser Reihenfolge sein, aber es könnte sein1,3,6
. Ich habe hier um die Hilfe der Community bei der Verbesserung der integrierten Funktion gebeten:Bei ausreichendem qualitativen Feedback können sie tatsächlich einige dieser Verbesserungen in Betracht ziehen:
Weitere Informationen zu Teilungsfunktionen, warum (und beweisen Sie dies), während Schleifen und rekursive CTEs nicht skaliert werden, und bessere Alternativen, wenn Zeichenfolgen aus der Anwendungsschicht aufgeteilt werden:
Auf SQL Server 2016 oder höher, obwohl sollte man sich
STRING_SPLIT()
undSTRING_AGG()
:quelle
select * from DBO.SplitString('Hello John smith', ' ');
und die erzeugte Ausgabe war: Wert Hallo ello llo lo o John ohn hn nSie können eine Zahlentabelle nutzen, um die Zeichenfolge zu analysieren.
Erstellen Sie eine Tabelle mit physischen Zahlen:
Erstellen Sie eine Testtabelle mit 1000000 Zeilen
Erstellen Sie die Funktion
Verwendung (gibt 3mil Zeilen in 40s auf meinem Laptop aus)
Aufräumen
Die Leistung hier ist nicht erstaunlich, aber das Aufrufen einer Funktion über eine Million Zeilentabellen ist nicht die beste Idee. Wenn ich eine Zeichenfolge auf mehrere Zeilen verteilen würde, würde ich die Funktion vermeiden.
quelle
desc
entfernt würden?REVERSE(PARSENAME(REPLACE(REVERSE('Hello John Smith'), ' ', '.'), 1))
@NothingsImpossible in 1,5 Minuten abgeschlossen war. @hello_earth Wie würde sich Ihre Lösung bei längeren Zeichenfolgen mit mehr als 4 Feldern vergleichen lassen?Bei dieser Frage geht es nicht um einen String-Split-Ansatz , sondern darum, wie das n-te Element erhalten wird .
Alle Antworten hier sind eine Art von String - Splitting zu tun Rekursion,
CTE
s, mehrereCHARINDEX
,REVERSE
undPATINDEX
, erfinden Funktionen, Aufruf für CLR Methoden, Zahlentabellen,CROSS APPLY
s ... Die meisten Antworten viele Zeilen Code.Aber - wenn Sie wirklich nur einen Ansatz wollen, um das n-te Element zu erhalten - kann dies als echter Einzeiler , ohne UDF, nicht einmal als Unterauswahl erfolgen ... und als zusätzlichen Vorteil: Typensicher
Holen Sie sich Teil 2 durch ein Leerzeichen begrenzt:
Natürlich können Sie Variablen für Trennzeichen und Position verwenden (verwenden Sie
sql:column
diese Option, um die Position direkt aus dem Wert einer Abfrage abzurufen):Wenn Ihre Zeichenfolge möglicherweise verbotene Zeichen enthält (insbesondere eines davon
&><
), können Sie dies dennoch auf diese Weise tun. VerwendenFOR XML PATH
Sie einfach zuerst Ihre Zeichenfolge, um alle verbotenen Zeichen implizit durch die passende Escape-Sequenz zu ersetzen.Es ist ein ganz besonderer Fall, wenn - zusätzlich - Ihr Trennzeichen das Semikolon ist . In diesem Fall ersetze ich das Trennzeichen zuerst durch '# DLMT #' und ersetze es schließlich durch die XML-Tags:
UPDATE für SQL-Server 2016+
Leider haben die Entwickler vergessen, den Index des Teils mit zurückzugeben
STRING_SPLIT
. Bei Verwendung von SQL-Server 2016+ gibt es jedochJSON_VALUE
undOPENJSON
.Mit können
JSON_VALUE
wir die Position als Index-Array übergeben.In
OPENJSON
der Dokumentation heißt es deutlich:Ein String wie
1,2,3
braucht nichts weiter als Klammern :[1,2,3]
.Eine Reihe von Wörtern wie
this is an example
muss sein["this","is","an","example"]
.Dies sind sehr einfache Zeichenfolgenoperationen. Probieren Sie es einfach aus:
--See dies für eine sichere Position strangTeiler ( Null-Basis ):
In diesem Beitrag habe ich verschiedene Ansätze getestet und festgestellt, dass
OPENJSON
das sehr schnell geht. Noch viel schneller als die berühmte Methode "delimitedSplit8k ()" ...UPDATE 2 - Holen Sie sich die Werte typsicher
Wir können ein Array innerhalb eines Arrays verwenden , indem wir einfach double verwenden
[[]]
. Dies ermöglicht eine typisierteWITH
Klausel:quelle
<x><![CDATA[x<&>x]]></x>
.CDATA
Abschnitte können sich auch damit befassen ... Aber nach der Besetzung sind sie weg (geändert, umtext()
implizit entkommen zu sein ). Ich mag keine Magie unter der Haube , deshalb würde ich den(SELECT 'Text with <&>' AS [*] FOR XML PATH(''))
Ansatz vorziehen . Das sieht für mich sauberer aus und passiert trotzdem ... (Noch etwas zu CDATA und XML ).Hier ist eine UDF, die das macht. Es wird eine Tabelle mit den begrenzten Werten zurückgegeben. Es wurden nicht alle Szenarien ausprobiert, aber Ihr Beispiel funktioniert einwandfrei.
Sie würden es so nennen:
Bearbeiten: Aktualisierte Lösung zur Behandlung von Trennzeichen mit einer Länge> 1 wie in:
quelle
Hier poste ich einen einfachen Lösungsweg
Führen Sie die Funktion folgendermaßen aus
quelle
Meiner Meinung nach macht ihr es viel zu kompliziert. Erstellen Sie einfach eine CLR-UDF und fertig.
quelle
Was ist mit Verwendung
string
undvalues()
Aussage?Ergebnismenge erreicht.
quelle
Ich verwende die Antwort von frederic, aber dies hat in SQL Server 2005 nicht funktioniert
Ich habe es geändert und ich benutze
select
mitunion all
und es funktioniertUnd die Ergebnismenge ist:
quelle
EXEC
.EXEC
Ruft implizit eine gespeicherte Prozedur auf, und Sie können gespeicherte Prozeduren in UDFs nicht verwenden.Dieses Muster funktioniert gut und Sie können verallgemeinern
Beachten Sie FELD , INDEX und TYP .
Lassen Sie eine Tabelle mit Bezeichnern wie
Dann können Sie schreiben
Teilen und Gießen aller Teile.
quelle
Wenn Ihre Datenbank eine Kompatibilitätsstufe von 130 oder höher aufweist, können Sie die Funktion STRING_SPLIT zusammen mit den Klauseln OFFSET FETCH verwenden , um das bestimmte Element nach Index abzurufen .
Um den Artikel auf Index N (basierend auf Null) zu erhalten, können Sie den folgenden Code verwenden
Führen Sie den folgenden Code aus, um die Kompatibilitätsstufe Ihrer Datenbank zu überprüfen :
quelle
xml
Gut zu wissen ... Ich würde immer noch den auf -split basierenden Ansatz bevorzugen , da er das Abrufen des Werttyps sicher ermöglicht und keine Unterabfrage benötigt, aber dies ist eine gut. +1 von meiner SeiteSTRING_SPLIT
Anforderungen für v2016 +. In diesem Fall ist es viel besser,OPENJSON
oder zu verwendenJSON_VALUE
. Vielleicht möchten Sie meine Antwort überprüfenIch habe im Internet nach der Lösung gesucht und das Folgende funktioniert für mich. Ref .
Und Sie rufen die Funktion folgendermaßen auf:
quelle
Noch ein weiterer Teil des Strings per Delimeter:
und die Verwendung:
was zurückgibt:
quelle
Versuche dies:
Testen Sie es so:
quelle
Im folgenden Beispiel wird ein rekursiver CTE verwendet
Update 18.09.2013
Demo auf SQLFiddle
quelle
quelle
Sie können eine Zeichenfolge in SQL teilen, ohne eine Funktion zu benötigen:
Wenn Sie beliebige Zeichenfolgen unterstützen müssen (mit XML-Sonderzeichen)
quelle
Ich weiß, dass es eine alte Frage ist, aber ich denke, jemand kann von meiner Lösung profitieren.
SQL FIDDLE
Vorteile:
Einschränkungen:
Hinweis : Die Lösung kann Teilzeichenfolgen bis zu N geben.
Um die Einschränkung zu überwinden, können wir die folgende Referenz verwenden .
Aber auch hier kann die obige Lösung nicht in einer Tabelle verwendet werden (Actaully konnte ich sie nicht verwenden).
Wieder hoffe ich, dass diese Lösung jemandem helfen kann.
Update: Bei Datensätzen> 50000 ist die Verwendung nicht ratsam ,
LOOPS
da dies die Leistung beeinträchtigtquelle
Reine satzbasierte Lösung
TVF
mit rekursivCTE
. Sie könnenJOIN
undAPPLY
diese Funktion zu jedem Datensatz.Verwendungszweck:
Ergebnis:
quelle
Fast alle anderen Antworten ersetzen die zu teilende Zeichenfolge, wodurch CPU-Zyklen verschwendet werden und unnötige Speicherzuweisungen durchgeführt werden.
Ich beschreibe hier einen viel besseren Weg, um einen String-Split durchzuführen: http://www.digitalruby.com/split-string-sql-server/
Hier ist der Code:
quelle
Rekursive CTE-Lösung mit Serverschmerzen, testen Sie sie
MS SQL Server 2008 Schema-Setup :
Abfrage 1 :
Ergebnisse :
quelle
Während ich der XML-basierten Antwort von Josejuan ähnlich war, stellte ich fest, dass die Verarbeitung des XML-Pfads nur einmal und das Schwenken mäßig effizienter war:
lief in 8:30
lief in 9:20
quelle
UND BENUTZEN SIE ES
quelle
Wenn jemand nur einen Teil des Textes erhalten möchte, kann er dies verwenden
Wählen Sie * aus fromSplitStringSep ('Word1 wordr2 word3', '').
quelle
Ich habe das entwickelt,
Die einzige Aufmerksamkeit, die Sie beachten sollten, ist Punkt '.' Das Ende des @x sollte immer da sein.
quelle
Aufbauend auf der @ NotingsImpossible-Lösung oder besser gesagt auf der am meisten bewerteten Antwort (knapp unter der akzeptierten) stellte ich fest, dass die folgende schnelle und schmutzige Lösung meine eigenen Anforderungen erfüllt - sie hat den Vorteil, dass sie ausschließlich innerhalb der SQL-Domäne liegt.
Wenn ich eine Zeichenfolge "erste; zweite; dritte; vierte; fünfte" gebe, möchte ich beispielsweise die dritte Zeichenfolge erhalten. Dies funktioniert nur, wenn wir wissen, wie viele Token die Zeichenfolge haben wird - in diesem Fall ist es 5. Meine Vorgehensweise besteht also darin, die letzten beiden Token wegzuschneiden (innere Abfrage) und dann die ersten beiden Token wegzuschneiden (innere Abfrage). äußere Abfrage)
Ich weiß, dass dies hässlich ist und die spezifischen Bedingungen abdeckt, in denen ich war, aber ich poste es nur für den Fall, dass jemand es nützlich findet. Prost
quelle
quelle
Ab SQL Server 2016 haben wir string_split
quelle
STRING_SPLIT
garantiert nicht die Rücksendung der gleichen Bestellung. AberOPENJSON
tut (siehe meine Antwort (Update-Abschnitt) )