Ich finde eine Möglichkeit, Zeichenfolgen aus verschiedenen Zeilen in einer einzigen Zeile zusammenzufassen. Ich möchte dies an vielen verschiedenen Orten tun, daher wäre es schön, eine Funktion zu haben, die dies erleichtert. Ich habe Lösungen mit COALESCE
und ausprobiert FOR XML
, aber sie schneiden es einfach nicht für mich.
Die String-Aggregation würde ungefähr so aussehen:
id | Name Result: id | Names
-- - ---- -- - -----
1 | Matt 1 | Matt, Rocks
1 | Rocks 2 | Stylus
2 | Stylus
Ich habe mir CLR-definierte Aggregatfunktionen als Ersatz für COALESCE
und angesehen FOR XML
, aber anscheinend unterstützt SQL Azure keine CLR-definierten Funktionen, was für mich ein Schmerz ist, da ich weiß, dass die Verwendung eine ganze Menge davon lösen würde Probleme für mich.
Gibt es eine mögliche Abhilfe, oder in ähnlicher Weise eine optimale Verfahren (die als optimal nicht als CLR sein könnte, aber hey ich nehme , was ich kriegen kann) , dass ich verwenden kann , meine Sachen zu aggregieren?
for xml
funktioniert das bei Ihnen nicht?for xml
zeigt eine 25% ige Auslastung in Bezug auf die Abfrageleistung (ein Großteil der Abfrage!)for xml path
Abfrage durchzuführen. Einige schneller als andere. Es könnte von Ihren Daten abhängen, aber die verwendetendistinct
sind meiner Erfahrung nach langsamer als diegroup by
. Und wenn Sie verwenden.value('.', nvarchar(max))
, um die verketteten Werte zu erhalten, sollten Sie dies in.value('./text()[1]', nvarchar(max))
Antworten:
LÖSUNG
Die Definition von optimal kann variieren. Hier erfahren Sie jedoch, wie Sie Zeichenfolgen aus verschiedenen Zeilen mithilfe von regulärem Transact SQL verketten, was in Azure problemlos funktionieren sollte.
ERLÄUTERUNG
Der Ansatz besteht aus drei Schritten:
Nummerieren Sie die Zeilen mit
OVER
undPARTITION
gruppieren und ordnen Sie sie nach Bedarf für die Verkettung. Das Ergebnis istPartitioned
CTE. Wir behalten die Anzahl der Zeilen in jeder Partition bei, um die Ergebnisse später zu filtern.Verwenden Sie rekursives CTE (
Concatenated
), um die Zeilennummern (NameNumber
Spalte) zu durchlaufen und der SpalteName
Werte hinzuzufügenFullName
.Filtern Sie alle Ergebnisse außer denen mit den höchsten heraus
NameNumber
.Bitte beachten Sie, dass Sie, um diese Abfrage vorhersehbar zu machen, sowohl die Gruppierung (z. B. in Ihrem Szenario werden Zeilen mit derselben
ID
verkettet) als auch die Sortierung definieren müssen (ich habe angenommen, dass Sie die Zeichenfolge vor der Verkettung einfach alphabetisch sortieren).Ich habe die Lösung unter SQL Server 2012 schnell mit den folgenden Daten getestet:
Das Abfrageergebnis:
quelle
Sind Methoden, die FOR XML PATH wie unten verwenden, wirklich so langsam? Itzik Ben-Gan schreibt, dass diese Methode in seinem T-SQL-Abfragebuch eine gute Leistung aufweist (Herr Ben-Gan ist meiner Ansicht nach eine vertrauenswürdige Quelle).
quelle
id
Spalte zu erstellen , sobald die Größe einer Tabelle zum Problem wird.&
umgeschaltet auf&
usw.). Eine korrekterefor xml
Lösung finden Sie hier .Für diejenigen von uns, die dies gefunden haben
und verwenden keine Azure SQL-Datenbank::STRING_AGG()
in PostgreSQL, SQL Server 2017 und Azure SQLhttps://www.postgresql.org/docs/current/static/functions-aggregate.html
https://docs.microsoft.com/en-us/sql/t-sql/ Funktionen / string-agg-transact-sql
GROUP_CONCAT()
in MySQLhttp://dev.mysql.com/doc/refman/5.7/de/group-by-functions.html#function_group-concat
(Danke an @Brianjorden und @milanio für das Azure-Update)
Beispielcode:
SQL Fiddle: http://sqlfiddle.com/#!18/89251/1
quelle
STRING_AGG
wurde auf 2017 zurückgeschoben. Es ist nicht verfügbar in 2016.Obwohl die Antwort von @serge korrekt ist, habe ich den Zeitverbrauch seines Weges mit xmlpath verglichen und festgestellt, dass der xmlpath so schneller ist. Ich werde den Vergleichscode schreiben und Sie können ihn selbst überprüfen. Dies ist @serge Weg:
Und das ist xmlpath Weg:
quelle
Update: Frau SQL Server 2017+, Azure SQL-Datenbank
Sie können verwenden :
STRING_AGG
.Die Verwendung ist für die Anfrage von OP ziemlich einfach:
Weiterlesen
Nun, meine alte Nichtantwort wurde zu Recht gelöscht (unten in Kontakt gelassen), aber wenn jemand in Zukunft hier landet, gibt es gute Nachrichten. Sie haben STRING_AGG () auch in die Azure SQL-Datenbank implementiert. Dies sollte die genaue Funktionalität bieten, die ursprünglich in diesem Beitrag angefordert wurde, und native und integrierte Unterstützung bieten. @hrobky erwähnte dies zu diesem Zeitpunkt bereits als SQL Server 2016-Funktion.
--- Alter Beitrag: Nicht genug Ruf hier, um direkt auf @hrobky zu antworten, aber STRING_AGG sieht gut aus, ist jedoch derzeit nur in SQL Server 2016 vNext verfügbar. Hoffentlich folgt bald auch Azure SQL Datababse.
quelle
STRING_AGG()
soll in SQL Server 2017 in jeder Kompatibilitätsstufe verfügbar sein. docs.microsoft.com/en-us/sql/t-sql/functions/…Sie können + = verwenden, um Zeichenfolgen zu verketten, zum Beispiel:
Wenn Sie @test auswählen, werden alle Namen verkettet
quelle
select @test += name + ', ' from names
ORDER BY
in Ihrer Abfrage haben. Sie sollten eine der aufgeführten Alternativen verwenden.Ich fand die Antwort von Serge sehr vielversprechend, stieß aber auch auf Leistungsprobleme, wie geschrieben. Als ich es jedoch umstrukturierte, um temporäre Tabellen zu verwenden und keine doppelten CTE-Tabellen einzuschließen, stieg die Leistung für 1000 kombinierte Datensätze von 1 Minute 40 Sekunden auf unter Sekunden. Hier ist es für alle, die dies ohne FOR XML in älteren Versionen von SQL Server tun müssen:
quelle