Wie verkette ich Text aus mehreren Zeilen in einer einzigen Textzeichenfolge in SQL Server?

1913

Stellen Sie sich eine Datenbanktabelle mit Namen und drei Zeilen vor:

Peter
Paul
Mary

Gibt es eine einfache Möglichkeit, daraus eine einzelne Zeichenfolge zu machen Peter, Paul, Mary?

JohnnyM
quelle
26
Versuchen Sie diese Frage , um spezifische Antworten für SQL Server zu erhalten .
Matt Hamilton
17
Für MySQL, überprüfen Sie Group_Concat aus dieser Antwort
Pykler
26
Ich wünschte, die nächste Version von SQL Server würde eine neue Funktion bieten, um die mehrzeilige String-Konkatination elegant zu lösen, ohne die Albernheit von FOR XML PATH.
Pete Alvin
4
Nicht SQL, aber wenn dies nur einmal vorkommt, können Sie die Liste in dieses In-Browser-Tool convert.town/column-to-comma-separated-list
Stack Man
3
In Oracle können Sie LISTAGG (COLUMN_NAME) von 11g r2 verwenden, bevor es eine nicht unterstützte Funktion namens WM_CONCAT (COLUMN_NAME) gibt, die dasselbe tut.
Richard

Antworten:

1432

Wenn Sie mit SQL Server 2017 oder Azure arbeiten, lesen Sie die Antwort von Mathieu Renda .

Ich hatte ein ähnliches Problem, als ich versuchte, zwei Tabellen mit Eins-zu-Viele-Beziehungen zu verbinden. In SQL 2005 habe ich festgestellt, dass diese XML PATHMethode die Verkettung der Zeilen sehr einfach handhaben kann.

Wenn eine Tabelle aufgerufen wird STUDENTS

SubjectID       StudentName
----------      -------------
1               Mary
1               John
1               Sam
2               Alaina
2               Edward

Ergebnis, das ich erwartet hatte, war:

SubjectID       StudentName
----------      -------------
1               Mary, John, Sam
2               Alaina, Edward

Ich habe folgendes verwendet T-SQL:

SELECT Main.SubjectID,
       LEFT(Main.Students,Len(Main.Students)-1) As "Students"
FROM
    (
        SELECT DISTINCT ST2.SubjectID, 
            (
                SELECT ST1.StudentName + ',' AS [text()]
                FROM dbo.Students ST1
                WHERE ST1.SubjectID = ST2.SubjectID
                ORDER BY ST1.SubjectID
                FOR XML PATH ('')
            ) [Students]
        FROM dbo.Students ST2
    ) [Main]

Sie können dasselbe auf kompaktere Weise tun, wenn Sie die Kommas am Anfang zusammenfassen und substringdas erste überspringen können, damit Sie keine Unterabfrage durchführen müssen:

SELECT DISTINCT ST2.SubjectID, 
    SUBSTRING(
        (
            SELECT ','+ST1.StudentName  AS [text()]
            FROM dbo.Students ST1
            WHERE ST1.SubjectID = ST2.SubjectID
            ORDER BY ST1.SubjectID
            FOR XML PATH ('')
        ), 2, 1000) [Students]
FROM dbo.Students ST2
StefanJCollier
quelle
13
Tolle Lösung. Folgendes kann hilfreich sein, wenn Sie Sonderzeichen wie in HTML behandeln müssen: Rob Farley: Umgang mit Sonderzeichen mit FOR XML PATH ('') .
10
Anscheinend funktioniert dies nicht, wenn die Namen XML-Zeichen wie <oder enthalten &. Siehe @ BenHinmans Kommentar.
Sam
23
NB: Diese Methode ist abhängig von undokumentiertem Verhalten von FOR XML PATH (''). Das bedeutet, dass es nicht als zuverlässig angesehen werden sollte, da Patches oder Updates die Funktionsweise ändern könnten. Es basiert im Grunde auf einer veralteten Funktion.
Bacon Bits
26
@Whelkaholism Unter dem Strich FOR XMLsoll XML generiert und keine beliebigen Zeichenfolgen verkettet werden. Deshalb ist es entweicht &, <und >auf XML - Entity - Codes ( &amp;, &lt;, &gt;). Ich gehe davon aus, dass es auch entkommen wird "und 'zu &quot;und &apos;in Attributen. Es ist nicht GROUP_CONCAT() , string_agg(), array_agg(), listagg(), usw. , auch wenn Sie Art macht es tun. Wir sollten unsere Zeit damit verbringen, von Microsoft die Implementierung einer ordnungsgemäßen Funktion zu fordern.
Bacon Bits
13
Gute Nachrichten: MS SQL Server wird string_aggin v.Next hinzufügen . und all dies kann verschwinden.
Jason C
1009

Diese Antwort kann zu unerwarteten Ergebnissen führen. Verwenden Sie für konsistente Ergebnisse eine der in anderen Antworten beschriebenen FOR XML PATH-Methoden.

Verwendung COALESCE:

DECLARE @Names VARCHAR(8000) 
SELECT @Names = COALESCE(@Names + ', ', '') + Name 
FROM People

Nur eine Erklärung (da diese Antwort relativ regelmäßige Ansichten zu bekommen scheint):

  • Coalesce ist wirklich nur ein hilfreicher Cheat, der zwei Dinge erreicht:

1) Keine Notwendigkeit, @Namesmit einem leeren Zeichenfolgenwert zu initialisieren .

2) Am Ende muss kein zusätzlicher Abscheider entfernt werden.

  • Die Lösung oben wird falsche Ergebnisse geben , wenn eine Zeile einen hat NULL - Name - Wert (wenn es eine ist NULL , die NULL machen @Names NULL nach dieser Zeile und die nächste Zeile wird wieder als eine leere Zeichenfolge beginnen. Einfach mit einem von zwei festen Lösungen:
DECLARE @Names VARCHAR(8000) 
SELECT @Names = COALESCE(@Names + ', ', '') + Name
FROM People
WHERE Name IS NOT NULL

oder:

DECLARE @Names VARCHAR(8000) 
SELECT @Names = COALESCE(@Names + ', ', '') + 
    ISNULL(Name, 'N/A')
FROM People

Je nachdem, welches Verhalten Sie möchten (die erste Option filtert nur NULL- Werte heraus, die zweite Option hält sie in der Liste mit einer Markierungsnachricht [ersetzen Sie 'N / A' durch die für Sie geeignete]).

Chris Shaffer
quelle
72
Um klar zu sein, hat Coalesce nichts mit dem Erstellen der Liste zu tun, sondern stellt lediglich sicher, dass keine NULL-Werte enthalten sind.
Graeme Perrow
17
@Graeme Perrow NULL-Werte werden nicht ausgeschlossen (dafür ist ein WHERE erforderlich - dies geht verloren, wenn einer der Eingabewerte NULL ist). Dies ist bei diesem Ansatz erforderlich, weil: NULL + Nicht-NULL -> NULL und nicht NULL + NULL -> NULL; Außerdem ist @Name standardmäßig NULL, und tatsächlich wird diese Eigenschaft hier als impliziter Sentinel verwendet, um zu bestimmen, ob ein ',' hinzugefügt werden soll oder nicht.
62
Beachten Sie, dass diese Verkettungsmethode davon abhängt, dass SQL Server die Abfrage mit einem bestimmten Plan ausführt. Ich wurde mit dieser Methode erwischt (mit der Hinzufügung eines ORDER BY). Wenn es sich um eine kleine Anzahl von Zeilen handelte, funktionierte es einwandfrei, aber mit mehr Daten wählte SQL Server einen anderen Plan, was dazu führte, dass das erste Element ohne jegliche Verkettung ausgewählt wurde. Siehe diesen Artikel von Anith Sen.
fbarber
17
Diese Methode kann nicht als Unterabfrage in einer Auswahlliste oder einer where-Klausel verwendet werden, da sie eine tSQL-Variable verwendet. In solchen Fällen können Sie die von @Ritesh
R. Schreurs
11
Dies ist keine zuverlässige Verkettungsmethode. Es wird nicht unterstützt und sollte nicht verwendet werden (laut Microsoft, z. B. support.microsoft.com/en-us/kb/287515 , connect.microsoft.com/SQLServer/Feedback/Details/704389 ). Es kann sich ohne Vorwarnung ändern. Verwenden Sie die XML-PATH-Technik, die unter stackoverflow.com/questions/5031204/… beschrieben wurde. Ich habe hier mehr geschrieben: marc.durdin.net/2015/07/…
Marc Durdin
454

SQL Server 2017+ und SQL Azure: STRING_AGG

Ab der nächsten Version von SQL Server können wir endlich zeilenübergreifend verketten, ohne auf Variablen oder XML-Hexerei zurückgreifen zu müssen.

STRING_AGG (Transact-SQL)

Ohne Gruppierung

SELECT STRING_AGG(Name, ', ') AS Departments
FROM HumanResources.Department;

Mit Gruppierung:

SELECT GroupName, STRING_AGG(Name, ', ') AS Departments
FROM HumanResources.Department
GROUP BY GroupName;

Mit Gruppierung und Untersortierung

SELECT GroupName, STRING_AGG(Name, ', ') WITHIN GROUP (ORDER BY Name ASC) AS Departments
FROM HumanResources.Department 
GROUP BY GroupName;
Mathieu Renda
quelle
2
Und im Gegensatz zu CLR-Lösungen haben Sie die Kontrolle über die Sortierung.
Kanon
STRING_AGG
InspiredBy
Gibt es eine Möglichkeit zum Sortieren, falls es kein GROUP BY gibt (also für das Beispiel "Ohne Gruppierung")?
RuudvK
Update: Ich habe Folgendes geschafft, aber gibt es einen saubereren Weg? SELECT STRING_AGG (Name, ',') AS Abteilungen FROM (SELECT TOP 100000 Name FROM HumanResources.Department ORDER BY Name) D;
RuudvK
362

Eine Methode, die über den XML data()Befehl in MS SQL Server noch nicht angezeigt wird, ist:

Angenommen, die Tabelle heißt NameList mit einer Spalte namens FName.

SELECT FName + ', ' AS 'data()' 
FROM NameList 
FOR XML PATH('')

kehrt zurück:

"Peter, Paul, Mary, "

Es muss nur das zusätzliche Komma behandelt werden.

Bearbeiten: Wie aus @ NReilinghs Kommentar übernommen, können Sie das folgende Komma mit der folgenden Methode entfernen. Unter der Annahme der gleichen Tabellen- und Spaltennamen:

STUFF(REPLACE((SELECT '#!' + LTRIM(RTRIM(FName)) AS 'data()' FROM NameList
FOR XML PATH('')),' #!',', '), 1, 2, '') as Brands
jens frandsen
quelle
15
Heilige, das ist unglaublich! Wenn das Ergebnis wie in Ihrem Beispiel alleine ausgeführt wird, wird es als Hyperlink formatiert. Wenn Sie darauf klicken (in SSMS), wird ein neues Fenster mit den Daten geöffnet. Bei Verwendung als Teil einer größeren Abfrage wird es jedoch nur als Zeichenfolge angezeigt. Ist es eine Schnur? oder ist es XML, das ich in der Anwendung, die diese Daten verwendet, anders behandeln muss?
Ben
10
Dieser Ansatz entzieht auch XML-Zeichen wie <und>. Wenn Sie also '<b>' + FName + '</ b>' auswählen, erhalten Sie "& lt; b & gt; John & lt; / b & gt; b & gt; Paul ..."
Lukáš Lánský
8
Ordentliche Lösung. Ich stelle fest, dass selbst wenn ich das nicht hinzufüge, + ', 'zwischen jedem verketteten Element immer noch ein Leerzeichen eingefügt wird.
Baodad
8
@ Baodad Das scheint Teil des Deals zu sein. Sie können das Problem umgehen, indem Sie ein hinzugefügtes Token-Zeichen ersetzen. Zum Beispiel macht dies eine perfekte durch Kommas getrennte Liste für jede Länge:SELECT STUFF(REPLACE((SELECT '#!'+city AS 'data()' FROM #cityzip FOR XML PATH ('')),' #!',', '),1,2,'')
NReilingh
1
Wow, tatsächlich ist in meinen Tests mit data () und einem Ersatz viel leistungsfähiger als nicht. Super komisch.
NReilingh
306

In SQL Server 2005

SELECT Stuff(
  (SELECT N', ' + Name FROM Names FOR XML PATH(''),TYPE)
  .value('text()[1]','nvarchar(max)'),1,2,N'')

In SQL Server 2016

Sie können die FOR JSON-Syntax verwenden

dh

SELECT per.ID,
Emails = JSON_VALUE(
   REPLACE(
     (SELECT _ = em.Email FROM Email em WHERE em.Person = per.ID FOR JSON PATH)
    ,'"},{"_":"',', '),'$[0]._'
) 
FROM Person per

Und das Ergebnis wird

Id  Emails
1   abc@gmail.com
2   NULL
3   def@gmail.com, xyz@gmail.com

Dies funktioniert auch dann, wenn Ihre Daten ungültige XML-Zeichen enthalten

Das '"},{"_":"'ist sicher, denn wenn Sie Daten enthalten '"},{"_":"',, werden diese maskiert"},{\"_\":\"

Sie können durch ein ', 'beliebiges String-Trennzeichen ersetzen


Und in SQL Server 2017 Azure SQL-Datenbank

Sie können die neue Funktion STRING_AGG verwenden

Steven Chong
quelle
3
Gute Verwendung der STUFF-Funktion, um die beiden führenden Zeichen zu mischen.
David
3
Diese Lösung gefällt mir am besten, da ich sie problemlos in einer Auswahlliste verwenden kann, indem ich 'als <Label>' anhänge. Ich bin mir nicht sicher, wie ich das mit der Lösung von @Ritesh machen soll.
R. Schreurs
13
Das ist besser als die akzeptierte Antwort , weil diese Option auch un-Flucht XML reserverd Zeichen wie Griffe <, >, &usw. , die FOR XML PATH('')automatisch entweicht.
BateTech
Dies ist eine großartige Antwort, da sie das Problem behoben hat und die besten Möglichkeiten bietet, Dinge in verschiedenen SQL-Versionen zu tun. Ich wünschte, ich könnte 2017 / Azure
Chris Ward
120

In MySQL gibt es eine Funktion, GROUP_CONCAT () , mit der Sie die Werte aus mehreren Zeilen verketten können. Beispiel:

SELECT 1 AS a, GROUP_CONCAT(name ORDER BY name ASC SEPARATOR ', ') AS people 
FROM users 
WHERE id IN (1,2,3) 
GROUP BY a
Darryl Hein
quelle
funktioniert gut. Aber wenn ich benutze, SEPARATOR '", "'werde ich am Ende des letzten Eintrags einige Zeichen vermissen. Warum kann das passieren?
Gooleem
@gooleem Mir ist nicht klar, was du meinst, aber diese Funktion setzt nur das Trennzeichen zwischen Elementen, nicht danach. Wenn dies nicht die Antwort ist, würde ich empfehlen, eine neue Frage zu stellen.
Darryl Hein
@DarrylHein für meine Bedürfnisse habe ich den Separator wie oben verwendet. Aber das schneidet mir am Ende der Ausgabe ein paar Zeichen. Das ist sehr seltsam und scheint ein Fehler zu sein. Ich habe keine Lösung, ich habe nur umgangen.
Gooleem
Funktioniert grundsätzlich. Zwei Dinge zu beachten: 1) Wenn Ihre Spalte keine ist CHAR, müssen Sie sie umwandeln , z. B. über GROUP_CONCAT( CAST(id AS CHAR(8)) ORDER BY id ASC SEPARATOR ',')2) Wenn viele Werte kommen, sollten Sie group_concat_max_lendie in stackoverflow.com/a/1278210/1498405
hardmooth
58

Verwenden Sie COALESCE - Erfahren Sie hier mehr

Zum Beispiel:

102

103

104

Dann schreiben Sie unten Code in SQL Server,

Declare @Numbers AS Nvarchar(MAX) -- It must not be MAX if you have few numbers 
SELECT  @Numbers = COALESCE(@Numbers + ',', '') + Number
FROM   TableName where Number IS NOT NULL

SELECT @Numbers

Ausgabe wäre:

102,103,104
pedram
quelle
2
Dies ist wirklich die beste Lösung IMO, da sie die Codierungsprobleme vermeidet, die FOR XML darstellt. Ich habe verwendet Declare @Numbers AS Nvarchar(MAX)und es hat gut funktioniert. Können Sie bitte erklären, warum Sie empfehlen, es nicht zu verwenden?
EvilDr
7
Diese Lösung wurde bereits vor 8 Jahren veröffentlicht! stackoverflow.com/a/194887/986862
Andre Figueiredo
Warum wird diese Abfrage zurückgegeben? Symbole statt kyrillischer? Ist das nur ein Ausgabeproblem?
Akmal Salikhov
48

Postgres-Arrays sind fantastisch. Beispiel:

Erstellen Sie einige Testdaten:

postgres=# \c test
You are now connected to database "test" as user "hgimenez".
test=# create table names (name text);
CREATE TABLE                                      
test=# insert into names (name) values ('Peter'), ('Paul'), ('Mary');                                                          
INSERT 0 3
test=# select * from names;
 name  
-------
 Peter
 Paul
 Mary
(3 rows)

Aggregieren Sie sie in einem Array:

test=# select array_agg(name) from names;
 array_agg     
------------------- 
 {Peter,Paul,Mary}
(1 row)

Konvertieren Sie das Array in eine durch Kommas getrennte Zeichenfolge:

test=# select array_to_string(array_agg(name), ', ') from names;
 array_to_string
-------------------
 Peter, Paul, Mary
(1 row)

ERLEDIGT

Seit PostgreSQL 9.0 ist es noch einfacher .

hgmnz
quelle
Wenn Sie mehr als eine Spalte benötigen, zum Beispiel die Mitarbeiter-ID in Klammern, verwenden Sie den Concat-Operator: select array_to_string(array_agg(name||'('||id||')'
Richard Fox
Gilt nicht für SQL Server , nur für MySQL
GoldBishop
46

Oracle 11g Release 2 unterstützt die LISTAGG-Funktion. Dokumentation hier .

COLUMN employees FORMAT A50

SELECT deptno, LISTAGG(ename, ',') WITHIN GROUP (ORDER BY ename) AS employees
FROM   emp
GROUP BY deptno;

    DEPTNO EMPLOYEES
---------- --------------------------------------------------
        10 CLARK,KING,MILLER
        20 ADAMS,FORD,JONES,SCOTT,SMITH
        30 ALLEN,BLAKE,JAMES,MARTIN,TURNER,WARD

3 rows selected.

Warnung

Seien Sie vorsichtig bei der Implementierung dieser Funktion, wenn die Möglichkeit besteht, dass die resultierende Zeichenfolge mehr als 4000 Zeichen umfasst. Es wird eine Ausnahme ausgelöst. Wenn dies der Fall ist, müssen Sie entweder die Ausnahme behandeln oder Ihre eigene Funktion ausführen, die verhindert, dass die verknüpfte Zeichenfolge mehr als 4000 Zeichen enthält.

Alex
quelle
1
Für ältere Versionen von Oracle ist wm_concat perfekt. Seine Verwendung wird im Linkgeschenk von Alex erklärt. Danke Alex!
toscanelli
LISTAGGfunktioniert perfekt! Lesen Sie einfach das hier verlinkte Dokument. wm_concatab Version 12c entfernt.
Asgs
34

Verwenden Sie in SQL Server 2005 und höher die folgende Abfrage, um die Zeilen zu verketten.

DECLARE @t table
(
    Id int,
    Name varchar(10)
)
INSERT INTO @t
SELECT 1,'a' UNION ALL
SELECT 1,'b' UNION ALL
SELECT 2,'c' UNION ALL
SELECT 2,'d' 

SELECT ID,
stuff(
(
    SELECT ','+ [Name] FROM @t WHERE Id = t.Id FOR XML PATH('')
),1,1,'') 
FROM (SELECT DISTINCT ID FROM @t ) t
Yogesh Bhadauirya
quelle
2
Ich glaube, dies schlägt fehl, wenn die Werte XML-Symbole wie <oder enthalten &.
Sam
28

Ich habe zu Hause keinen Zugriff auf einen SQL Server, daher schätze ich die Syntax hier, aber es ist mehr oder weniger:

DECLARE @names VARCHAR(500)

SELECT @names = @names + ' ' + Name
FROM Names
Dana
quelle
11
Sie müssten @names auf etwas setzen, das nicht null ist, sonst erhalten Sie durchgehend NULL. Sie müssten auch das Trennzeichen (einschließlich des unnötigen) behandeln
Marc Gravell
3
Das einzige Problem mit diesem Ansatz (den ich ständig verwende) ist, dass Sie ihn nicht einbetten können
ekkis
1
Um den führenden Platz loszuwerden, ändern Sie die Abfrage inSELECT @names = @names + CASE WHEN LEN(@names)=0 THEN '' ELSE ' ' END + Name FROM Names
Tian van Heerden
Außerdem müssen Sie überprüfen, ob der Name nicht null ist. Sie können dies tun, indem Sie SELECT @names = @names + ISNULL(' ' + Name, '')
Folgendes
28

Eine rekursive CTE-Lösung wurde vorgeschlagen, es wurde jedoch kein Code bereitgestellt. Der folgende Code ist ein Beispiel für einen rekursiven CTE. Beachten Sie, dass die Ergebnisse zwar mit der Frage übereinstimmen, die Daten jedoch nicht ganz mit der angegebenen Beschreibung übereinstimmen, da ich davon ausgehe, dass Sie dies wirklich für Zeilengruppen tun möchten, nicht für alle Zeilen in der Tabelle. Das Ändern so, dass es mit allen Zeilen in der Tabelle übereinstimmt, bleibt dem Leser als Übung.

;WITH basetable AS (
    SELECT
        id,
        CAST(name AS VARCHAR(MAX)) name, 
        ROW_NUMBER() OVER (Partition BY id ORDER BY seq) rw, 
        COUNT(*) OVER (Partition BY id) recs 
    FROM (VALUES
        (1, 'Johnny', 1),
        (1, 'M', 2), 
        (2, 'Bill', 1),
        (2, 'S.', 4),
        (2, 'Preston', 5),
        (2, 'Esq.', 6),
        (3, 'Ted', 1),
        (3, 'Theodore', 2),
        (3, 'Logan', 3),
        (4, 'Peter', 1),
        (4, 'Paul', 2),
        (4, 'Mary', 3)
    ) g (id, name, seq)
),
rCTE AS (
    SELECT recs, id, name, rw
    FROM basetable
    WHERE rw = 1

    UNION ALL

    SELECT b.recs, r.ID, r.name +', '+ b.name name, r.rw + 1
    FROM basetable b
    INNER JOIN rCTE r ON b.id = r.id AND b.rw = r.rw + 1
)
SELECT name
FROM rCTE
WHERE recs = rw AND ID=4
jmoreno
quelle
1
Für den Verblüfften: Diese Abfrage fügt 12 Zeilen (3 Spalten) in eine temporäre Basetabelle ein, erstellt dann einen rekursiven Common Table Expression (rCTE) und glättet die name Spalte dann in eine durch Kommas getrennte Zeichenfolge für 4 Gruppen von ids. Auf den ersten Blick denke ich, dass dies mehr Arbeit ist als die meisten anderen Lösungen für SQL Server.
Knb
2
@knb: Ich bin mir nicht sicher, ob das Lob, Verurteilung oder nur Überraschung ist. Die Basistabelle ist, weil ich möchte, dass meine Beispiele tatsächlich funktionieren, sie hat eigentlich nichts mit der Frage zu tun.
jmoreno
26

Ab PostgreSQL 9.0 ist dies ganz einfach:

select string_agg(name, ',') 
from names;

In Versionen vor 9.0 array_agg()kann wie von hgmnz gezeigt verwendet werden

ein Pferd ohne Name
quelle
Um dies mit Spalten zu tun, die nicht vom Typ Text sind, müssen Sie eine Typbesetzung hinzufügen:SELECT string_agg(non_text_type::text, ',') FROM table
Torben Kohlmeier
@TorbenKohlmeier: Das brauchen Sie nur für Nicht-Zeichen-Spalten (zB Ganzzahl, Dezimal). Es funktioniert gut für varcharoderchar
a_horse_with_no_name
26

Sie müssen eine Variable erstellen, die Ihr Endergebnis enthält, und diese wie folgt auswählen.

Einfachste Lösung

DECLARE @char VARCHAR(MAX);

SELECT @char = COALESCE(@char + ', ' + [column], [column]) 
FROM [table];

PRINT @char;
Tigerjz32
quelle
18

Die Verwendung von XML hat mir geholfen, Zeilen durch Kommas zu trennen. Für das zusätzliche Komma können wir die Ersetzungsfunktion von SQL Server verwenden. Anstatt ein Komma hinzuzufügen, verkettet die Verwendung des AS 'data ()' die Zeilen mit Leerzeichen, die später durch Kommas wie die unten beschriebene Syntax ersetzt werden können.

REPLACE(
        (select FName AS 'data()'  from NameList  for xml path(''))
         , ' ', ', ') 
Diwakar
quelle
2
Dies ist meiner Meinung nach die beste Antwort hier. Die Verwendung der Deklarationsvariablen ist nicht gut, wenn Sie einer anderen Tabelle beitreten müssen, und dies ist nett und kurz. Gute Arbeit.
David Roussel
7
Das funktioniert nicht gut, wenn FName-Daten bereits Leerzeichen enthalten, z. B. "Mein Name"
binball
Wirklich funktioniert es für mich auf ms-sql 2016 Wählen Sie REPLACE ((wählen Sie Name AS 'data ()' von Brand Where Id IN (1,2,3,4) für xml path ('')), '', ' , ') as allBrands
Rejwanul Reja
17

Eine gebrauchsfertige Lösung ohne zusätzliche Kommas:

select substring(
        (select ', '+Name AS 'data()' from Names for xml path(''))
       ,3, 255) as "MyList"

Eine leere Liste führt zu einem NULL-Wert. Normalerweise fügen Sie die Liste in eine Tabellenspalte oder Programmvariable ein: Passen Sie die maximale Länge von 255 an Ihre Bedürfnisse an.

(Diwakar und Jens Frandsen gaben gute Antworten, müssen aber verbessert werden.)

Daniel Reis
quelle
Es gibt ein Leerzeichen vor dem Komma, wenn dies verwendet wird :(
slayernoah
1
Ersetzen Sie einfach ', 'mit , ','wenn Sie nicht den zusätzlichen Platz wollen.
Daniel Reis
13
SELECT STUFF((SELECT ', ' + name FROM [table] FOR XML PATH('')), 1, 2, '')

Hier ist ein Beispiel:

DECLARE @t TABLE (name VARCHAR(10))
INSERT INTO @t VALUES ('Peter'), ('Paul'), ('Mary')
SELECT STUFF((SELECT ', ' + name FROM @t FOR XML PATH('')), 1, 2, '')
--Peter, Paul, Mary
Max Szczurek
quelle
10
DECLARE @Names VARCHAR(8000)
SELECT @name = ''
SELECT @Names = @Names + ',' + Names FROM People
SELECT SUBSTRING(2, @Names, 7998)

Dies setzt das Streukomma an den Anfang.

Wenn Sie jedoch andere Spalten benötigen oder eine untergeordnete Tabelle CSV-fähig machen möchten, müssen Sie diese in ein skalares benutzerdefiniertes Feld (UDF) einschließen.

Sie können den XML-Pfad auch als korrelierte Unterabfrage in der SELECT-Klausel verwenden (aber ich muss warten, bis ich wieder zur Arbeit gehe, da Google zu Hause keine Arbeit erledigt :-)

gbn
quelle
10

Bei den anderen Antworten muss die Person, die die Antwort liest, eine bestimmte Domänentabelle wie Fahrzeug oder Schüler kennen. Die Tabelle muss erstellt und mit Daten gefüllt werden, um eine Lösung zu testen.

Unten finden Sie ein Beispiel, das die SQL Server-Tabelle "Information_Schema.Columns" verwendet. Mit dieser Lösung müssen keine Tabellen erstellt oder Daten hinzugefügt werden. In diesem Beispiel wird eine durch Kommas getrennte Liste von Spaltennamen für alle Tabellen in der Datenbank erstellt.

SELECT
    Table_Name
    ,STUFF((
        SELECT ',' + Column_Name
        FROM INFORMATION_SCHEMA.Columns Columns
        WHERE Tables.Table_Name = Columns.Table_Name
        ORDER BY Column_Name
        FOR XML PATH ('')), 1, 1, ''
    )Columns
FROM INFORMATION_SCHEMA.Columns Tables
GROUP BY TABLE_NAME 
Mike Barlow - BarDev
quelle
7

Informationen zu Oracle-DBs finden Sie in dieser Frage: Wie können in Oracle mehrere Zeilen zu einer verknüpft werden, ohne dass eine gespeicherte Prozedur erstellt wird?

Die beste Antwort scheint @Emmanuel zu sein, der die integrierte Funktion LISTAGG () verwendet, die in Oracle 11g Release 2 und höher verfügbar ist.

SELECT question_id,
   LISTAGG(element_id, ',') WITHIN GROUP (ORDER BY element_id)
FROM YOUR_TABLE;
GROUP BY question_id

Wie @ user762952 hervorhob und laut Oracle-Dokumentation http://www.oracle-base.com/articles/misc/string-aggregation-techniques.php , ist die Funktion WM_CONCAT () ebenfalls eine Option. Es scheint stabil zu sein, aber Oracle empfiehlt ausdrücklich, es nicht für SQL-Anwendungen zu verwenden. Verwenden Sie es daher auf eigenes Risiko.

Ansonsten müssen Sie Ihre eigene Funktion schreiben. Das obige Oracle-Dokument enthält eine Anleitung dazu.

ZeroK
quelle
7

Um Nullwerte zu vermeiden, können Sie CONCAT () verwenden.

DECLARE @names VARCHAR(500)
SELECT @names = CONCAT(@names, ' ', name) 
FROM Names
select @names
Rapunzo
quelle
Es wäre schön zu wissen, warum CONCAT funktioniert. Ein Link zu MSDN wäre schön.
Umgekehrter Ingenieur
7

Ich mochte die Eleganz von Danas Antwort sehr . Ich wollte es nur vervollständigen.

DECLARE @names VARCHAR(MAX)
SET @names = ''

SELECT @names = @names + ', ' + Name FROM Names 

-- Deleting last two symbols (', ')
SET @sSql = LEFT(@sSql, LEN(@sSql) - 1)
Oleg Sacharow
quelle
Wenn Sie die letzten beiden Symbole ',' löschen, müssen Sie ',' nach Name hinzufügen ('SELECT \ @names = \ @names + Name +', 'FROM Names'). Auf diese Weise sind die letzten beiden Zeichen immer ','.
JT_
In meinem Fall musste ich das führende Komma entfernen, also ändern Sie die Abfrage in, SELECT @names = @names + CASE WHEN LEN(@names)=0 THEN '' ELSE ', ' END + Name FROM Namesdann müssen Sie sie danach nicht mehr abschneiden.
Tian van Heerden
6

Diese Antwort erfordert einige Berechtigungen auf dem Server, um zu funktionieren.

Baugruppen sind eine gute Option für Sie. Es gibt viele Websites, die erklären, wie man es erstellt. Der, den ich denke , ist sehr gut erklärt ist dies ein

Wenn Sie möchten, habe ich die Assembly bereits erstellt und Sie können die DLL hier herunterladen .

Nachdem Sie es heruntergeladen haben, müssen Sie das folgende Skript in Ihrem SQL Server ausführen:

CREATE Assembly concat_assembly 
   AUTHORIZATION dbo 
   FROM '<PATH TO Concat.dll IN SERVER>' 
   WITH PERMISSION_SET = SAFE; 
GO 

CREATE AGGREGATE dbo.concat ( 

    @Value NVARCHAR(MAX) 
  , @Delimiter NVARCHAR(4000) 

) RETURNS NVARCHAR(MAX) 
EXTERNAL Name concat_assembly.[Concat.Concat]; 
GO  

sp_configure 'clr enabled', 1;
RECONFIGURE

Beachten Sie, dass der Server möglicherweise auf den Pfad zur Assembly zugreifen kann. Da Sie alle Schritte erfolgreich ausgeführt haben, können Sie die folgende Funktion verwenden:

SELECT dbo.Concat(field1, ',')
FROM Table1

Ich hoffe es hilft!!!

Nizam
quelle
1
Die DLL-Verbindung ist ein 404-Fehler. Die Verwendung einer Baugruppe hierfür ist übertrieben. Siehe beste Antwort für SQL Server.
Protiguous
6

MySQL komplett Beispiel:

Wir haben Benutzer, die viele Daten haben können, und wir möchten eine Ausgabe haben, in der wir alle Benutzerdaten in einer Liste sehen können:

Ergebnis:

___________________________
| id   |  rowList         |
|-------------------------|
| 0    | 6, 9             |
| 1    | 1,2,3,4,5,7,8,1  |
|_________________________|

Tabelleneinrichtung:

CREATE TABLE `Data` (
  `id` int(11) NOT NULL,
  `user_id` int(11) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=latin1;


INSERT INTO `Data` (`id`, `user_id`) VALUES
(1, 1),
(2, 1),
(3, 1),
(4, 1),
(5, 1),
(6, 0),
(7, 1),
(8, 1),
(9, 0),
(10, 1);


CREATE TABLE `User` (
  `id` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;


INSERT INTO `User` (`id`) VALUES
(0),
(1);

Abfrage:

SELECT User.id, GROUP_CONCAT(Data.id ORDER BY Data.id) AS rowList FROM User LEFT JOIN Data ON User.id = Data.user_id GROUP BY User.id
user1767754
quelle
5

Normalerweise verwende ich select wie folgt, um Zeichenfolgen in SQL Server zu verketten:

with lines as 
( 
  select 
    row_number() over(order by id) id, -- id is a line id
    line -- line of text.
  from
    source -- line source
), 
result_lines as 
( 
  select 
    id, 
    cast(line as nvarchar(max)) line 
  from 
    lines 
  where 
    id = 1 
  union all 
  select 
    l.id, 
    cast(r.line + N', ' + l.line as nvarchar(max))
  from 
    lines l 
    inner join 
    result_lines r 
    on 
      l.id = r.id + 1 
) 
select top 1 
  line
from
  result_lines
order by
  id desc
Vladimir Nesterovsky
quelle
5

Wenn Sie sich mit Nullen befassen möchten, können Sie dies tun, indem Sie eine where-Klausel hinzufügen oder eine weitere COALESCE um die erste hinzufügen.

DECLARE @Names VARCHAR(8000) 
SELECT @Names = COALESCE(COALESCE(@Names + ', ', '') + Name, @Names) FROM People
Pramod
quelle
5

Das hat bei mir funktioniert ( SqlServer 2016 ):

SELECT CarNamesString = STUFF((
         SELECT ',' + [Name]
            FROM tbl_cars 
            FOR XML PATH('')
         ), 1, 1, '')

Hier ist die Quelle: https://www.mytecbits.com/

Und eine Lösung für MySql (da diese Seite in Google für MySql angezeigt wird)

SELECT [Name],
       GROUP_CONCAT(DISTINCT [Name]  SEPARATOR ',')
       FROM tbl_cars

Aus MySQL-Dokumentationen

Arash.Zandi
quelle
4

In Oracle ist es wm_concat. Ich glaube, diese Funktion ist in der 10g-Version und höher verfügbar .

user762952
quelle
4

Dies kann auch nützlich sein

create table #test (id int,name varchar(10))
--use separate inserts on older versions of SQL Server
insert into #test values (1,'Peter'), (1,'Paul'), (1,'Mary'), (2,'Alex'), (3,'Jack')

DECLARE @t VARCHAR(255)
SELECT @t = ISNULL(@t + ',' + name, name) FROM #test WHERE id = 1
select @t
drop table #test

kehrt zurück

Peter,Paul,Mary
endo64
quelle
5
Leider scheint dieses Verhalten nicht offiziell unterstützt zu werden. MSDN sagt: "Wenn auf eine Variable in einer Auswahlliste verwiesen wird, sollte ihr ein Skalarwert zugewiesen werden, oder die SELECT-Anweisung sollte nur eine Zeile zurückgeben." Und es gibt Leute, die Probleme beobachtet haben: sqlmag.com/sql-server/multi-row-variable-assignment-and-order
blueling