Come concatenare il testo da più righe in una singola stringa di testo in SQL Server?


1913

Considerare una tabella di database con nomi, con tre righe:

Peter
Paul
Mary

C'è un modo semplice per trasformarlo in una singola stringa di Peter, Paul, Mary?


26
Per risposte specifiche a SQL Server, prova questa domanda .
Matt Hamilton,

17
Per MySQL, dai un'occhiata a Group_Concat da questa risposta
Pykler,

26
Vorrei che la prossima versione di SQL Server offrisse una nuova funzionalità per risolvere elegantemente la concatinazione di stringhe multi-riga senza la stupidità di FOR XML PATH.
Pete Alvin,

4
Non SQL, ma se questa è una sola volta, puoi incollare l'elenco in questo strumento nel browser convert.town/column-to-comma-separated-list
Stack Man

3
In Oracle puoi usare LISTAGG (COLUMN_NAME) da 11g r2 prima che esista una funzione non supportata chiamata WM_CONCAT (COLUMN_NAME) che fa lo stesso.
Richard,

Risposte:


1432

Se si utilizza SQL Server 2017 o Azure, vedere la risposta di Mathieu Renda .

Ho avuto un problema simile quando stavo cercando di unire due tavoli con relazioni uno-a-molti. In SQL 2005 ho scoperto che il XML PATHmetodo può gestire molto facilmente la concatenazione delle righe.

Se esiste una tabella chiamata STUDENTS

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

Il risultato che mi aspettavo era:

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

Ho usato il seguente 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]

Puoi fare la stessa cosa in un modo più compatto se riesci a concatenare le virgole all'inizio e utilizzare substringper saltare il primo in modo da non dover eseguire una query secondaria:

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

13
Ottima soluzione Quanto segue può essere utile se è necessario gestire caratteri speciali come quelli in HTML: Rob Farley: gestione di caratteri speciali con FOR XML PATH ('') .

10
Apparentemente questo non funziona se i nomi contengono caratteri XML come <o &. Vedi il commento di @ BenHinman.
Sam,

23
NB: questo metodo dipende dal comportamento non documentato di FOR XML PATH (''). Ciò significa che non dovrebbe essere considerato affidabile in quanto qualsiasi patch o aggiornamento potrebbe alterare il modo in cui funziona. Fondamentalmente si basa su una funzione obsoleta.
Pezzi di pancetta

26
@Whelkaholism La linea di fondo è che ha lo FOR XMLscopo di generare XML, non concatenare stringhe arbitrarie. Ecco perché sfugge &, <e >ai codici di entità XML ( &amp;, &lt;, &gt;). Suppongo che anche sfuggirà "e 'per &quot;e &apos;negli attributi pure. Si Non GROUP_CONCAT() , string_agg(), array_agg(), listagg(), ecc, anche se è possibile tipo di fargli fare quello. Noi dovremmo spenderemo il nostro tempo chiedendo Microsoft implementare un corretto funzionamento.
Pezzi di pancetta

13
Buone notizie: MS SQL Server verrà aggiunto string_aggin v.Prossimo. e tutto questo può andare via.
Jason C,

1009

Questa risposta può restituire risultati imprevisti Per risultati coerenti, utilizzare uno dei metodi FOR XML PATH dettagliati in altre risposte.

Utilizzare COALESCE:

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

Solo qualche spiegazione (poiché questa risposta sembra avere viste relativamente regolari):

  • Coalesce è davvero solo un trucco utile che realizza due cose:

1) Non è necessario inizializzare @Namescon un valore stringa vuoto.

2) Non è necessario rimuovere un separatore aggiuntivo alla fine.

  • La soluzione sopra mostrerà risultati errati se una riga ha un valore NULL Name (se c'è un NULL , il NULL renderà @Names NULL dopo quella riga e la riga successiva ricomincerà da capo come stringa vuota. Facilmente risolto con una delle due soluzioni:
DECLARE @Names VARCHAR(8000) 
SELECT @Names = COALESCE(@Names + ', ', '') + Name
FROM People
WHERE Name IS NOT NULL

o:

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

A seconda del comportamento desiderato (la prima opzione filtra solo NULL , la seconda opzione li mantiene nell'elenco con un messaggio marcatore [sostituisci 'N / A' con tutto ciò che è appropriato per te]).


72
Per essere chiari, la coesione non ha nulla a che fare con la creazione dell'elenco, si assicura solo che i valori NULL non siano inclusi.
Graeme Perrow,

17
@Graeme Perrow Non esclude i valori NULL (è richiesto un WHERE per questo - questo perderà i risultati se uno dei valori di input è NULL), ed è richiesto in questo approccio perché: NULL + non-NULL -> NULL e non-NULL + NULL -> NULL; anche @Name è NULL per impostazione predefinita e, in effetti, quella proprietà viene utilizzata come sentinella implicita qui per determinare se un ',' debba essere aggiunto o meno.

62
Si noti che questo metodo di concatenazione si basa su SQL Server che esegue la query con un piano particolare. Sono stato sorpreso usando questo metodo (con l'aggiunta di un ORDER BY). Quando ha avuto a che fare con un numero limitato di righe ha funzionato bene ma con più dati SQL Server ha scelto un piano diverso che ha portato alla selezione del primo elemento senza alcuna concatenazione. Vedi questo articolo di Anith Sen.
fbarber

17
Questo metodo non può essere utilizzato come query secondaria in un elenco di selezione o clausola where, poiché utilizza una variabile tSQL. In questi casi è possibile utilizzare i metodi offerti da @Ritesh
R. Schreurs il

11
Questo non è un metodo affidabile di concatenazione. Non è supportato e non deve essere utilizzato (per Microsoft, ad esempio support.microsoft.com/en-us/kb/287515 , connect.microsoft.com/SQLServer/Feedback/Details/704389 ). Può cambiare senza preavviso. Usa la tecnica del PERCORSO XML discussa in stackoverflow.com/questions/5031204/… Ho scritto di più qui: marc.durdin.net/2015/07/…
Marc Durdin,

454

SQL Server 2017+ e SQL Azure: STRING_AGG

A partire dalla prossima versione di SQL Server, possiamo finalmente concatenare le righe senza ricorrere a variabili o stregonerie XML.

STRING_AGG (Transact-SQL)

Senza raggruppamento

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

Con raggruppamento:

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

Con raggruppamento e sotto-ordinamento

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

2
E, a differenza delle soluzioni CLR, hai il controllo sull'ordinamento.
canone il

Sembra che ci sia una limitazione di visualizzazione di 4000 caratteri su STRING_AGG
InspiredBy

C'è un modo per fare l'ordinamento nel caso in cui non ci sia GROUP BY (quindi per l'esempio "Senza raggruppamento")?
RuudvK,

Aggiornamento: sono riuscito a fare quanto segue, ma esiste un modo più pulito? SELEZIONA STRING_AGG (Nome, ',') AS Dipartimenti DA (SELEZIONA TOP 100000 Nome DA HumanResources.Department ORDINA PER Nome) D;
RuudvK,

362

Un metodo non ancora mostrato tramite il XML data()comando in MS SQL Server è:

Supponiamo che la tabella si chiami NameList con una colonna chiamata FName,

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

ritorna:

"Peter, Paul, Mary, "

Deve essere gestita solo la virgola aggiuntiva.

Modifica: come adottato dal commento di @ NReilingh, è possibile utilizzare il seguente metodo per rimuovere la virgola finale. Supponendo gli stessi nomi di tabella e colonna:

STUFF(REPLACE((SELECT '#!' + LTRIM(RTRIM(FName)) AS 'data()' FROM NameList
FOR XML PATH('')),' #!',', '), 1, 2, '') as Brands

15
santo s ** è incredibile! Se eseguito da solo, come nel tuo esempio, il risultato è formattato come un collegamento ipertestuale, che quando si fa clic (in SSMS) apre una nuova finestra contenente i dati, ma quando viene utilizzato come parte di una query più grande viene visualizzato solo come una stringa. È una stringa? o è xml che devo trattare diversamente nell'applicazione che utilizzerà questi dati?
Ben

10
Questo approccio sfugge anche a caratteri XML come <e>. Quindi, SELEZIONANDO '<b>' + FName + '</b>' si ottiene "& lt; b & gt; John & lt; / b & gt; & lt; b & gt; Paul ..."
Lukáš Lánský

8
Soluzione pulita. Sto notando che anche quando non lo aggiungo + ', 'aggiunge comunque un singolo spazio tra ogni elemento concatenato.
Baodad,

8
@Baodad Sembra essere parte dell'accordo. Puoi risolvere il problema sostituendo un carattere token aggiunto. Ad esempio, questo fa un perfetto elenco delimitato da virgole per qualsiasi lunghezza:SELECT STUFF(REPLACE((SELECT '#!'+city AS 'data()' FROM #cityzip FOR XML PATH ('')),' #!',', '),1,2,'')
NReilingh

1
Wow, in realtà nei miei test usando data () e una sostituzione è MOLTO più performante che no. Super strano.
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

puoi usare la sintassi FOR JSON

vale a dire

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

E il risultato diventerà

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

Ciò funzionerà anche se i tuoi dati contengono caratteri XML non validi

il '"},{"_":"'è sicuro perché se i dati contengono'"},{"_":"', sarà sfuggito a"},{\"_\":\"

È possibile sostituire ', 'con qualsiasi separatore di stringhe


E in SQL Server 2017, Database SQL di Azure

Puoi utilizzare la nuova funzione STRING_AGG


3
Buon uso della funzione STUFF per nixare i due caratteri iniziali.
David,

3
Mi piace di più questa soluzione, perché posso facilmente usarla in un elenco selezionato aggiungendo 'as <label>'. Non sono sicuro di come farlo con la soluzione di @Ritesh.
R. Schreurs,

13
Questo è meglio che la risposta accettata, perché questa opzione gestisce anche XML caratteri Riservata non-fuga, come <, >, &, ecc, che FOR XML PATH('')sfuggirà automaticamente.
BateTech,

Questa è una risposta fantastica in quanto ha risolto il problema e offre i modi migliori di fare le cose in diverse versioni di SQL ora vorrei poter usare 2017 / Azure
Chris Ward,

120

In MySQL è presente una funzione, GROUP_CONCAT () , che consente di concatenare i valori da più righe. Esempio:

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

funziona bene. Ma quando uso SEPARATOR '", "'mi mancheranno alcuni caratteri alla fine dell'ultima voce. perché può succedere?
Gooleem,

@gooleem Non sono chiaro su cosa intendi, ma questa funzione mette solo il separatore tra gli elementi, non dopo. Se questa non è la risposta, ti consiglio di pubblicare una nuova domanda.
Darryl Hein,

@DarrylHein per le mie esigenze ho usato il separatore come sopra. Ma questo mi taglia alcuni caratteri alla fine dell'output. Questo è molto strano e sembra essere un bug. Non ho una soluzione, ho appena lavorato.
Gooleem,

Funziona sostanzialmente. Due cose da considerare: 1) se la colonna non è una CHAR, è necessario lanciarlo, ad esempio tramite GROUP_CONCAT( CAST(id AS CHAR(8)) ORDER BY id ASC SEPARATOR ',')2) se si dispone di molti valori venire, è necessario aumentare il group_concat_max_lencome scritto in stackoverflow.com/a/1278210/1498405
hardmooth

58

Usa COALESCE - Scopri di più da qui

Per un esempio:

102

103

104

Quindi scrivere sotto il codice nel server SQL,

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

L'output sarebbe:

102,103,104

2
Questa è davvero la migliore soluzione IMO in quanto evita i problemi di codifica che FOR XML presenta. Ho usato Declare @Numbers AS Nvarchar(MAX)e ha funzionato bene. Puoi spiegare perché mi consiglia di non usarlo per favore?
EvilDr

7
Questa soluzione è già stata pubblicata 8 anni fa! stackoverflow.com/a/194887/986862
Andre Figueiredo,

Perché questa query restituisce ??? simboli invece di quelli cirillici? Questo è solo un problema di output?
Akmal Salikhov,

48

Gli array Postgres sono fantastici. Esempio:

Crea alcuni dati di test:

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)

Aggregali in un array:

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

Converti l'array in una stringa delimitata da virgole:

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

FATTO

Da PostgreSQL 9.0 è ancora più semplice .


Se hai bisogno di più di una colonna, ad esempio il loro ID impiegato tra parentesi usa l'operatore concat: select array_to_string(array_agg(name||'('||id||')'
Richard Fox,

Non applicabile a sql-server , solo a mysql
GoldBishop

46

Oracle 11g Release 2 supporta la funzione LISTAGG. Documentazione qui .

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.

avvertimento

Fare attenzione a implementare questa funzione se è possibile che la stringa risultante superi i 4000 caratteri. Genererà un'eccezione. In tal caso, è necessario gestire l'eccezione o eseguire il rollup della propria funzione che impedisce alla stringa unita di superare i 4000 caratteri.


1
Per le versioni precedenti di Oracle, wm_concat è perfetto. Il suo utilizzo è spiegato nel link regalo di Alex. Grazie Alex!
toscanelli,

LISTAGGfunziona perfettamente! Basta leggere il documento collegato qui. wm_concatrimosso dalla versione 12c in poi.
chiede il

34

In SQL Server 2005 e versioni successive, utilizzare la query seguente per concatenare le righe.

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

2
Credo che ciò fallisca quando i valori contengono simboli XML come <o &.
Sam,

28

Non ho accesso a un SQL Server a casa, quindi immagino che la sintassi qui, ma è più o meno:

DECLARE @names VARCHAR(500)

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

11
Avresti bisogno di init @names per qualcosa di non nullo, altrimenti otterrai NULL dappertutto; dovresti anche gestire il delimitatore (incluso quello superfluo)
Marc Gravell

3
l'unico problema con questo approccio (che uso sempre) è che non puoi incorporarlo
ekkis

1
Per sbarazzarsi dello spazio principale cambia la query inSELECT @names = @names + CASE WHEN LEN(@names)=0 THEN '' ELSE ' ' END + Name FROM Names
Tian van Heerden

Inoltre, devi controllare che Nome non sia nullo, puoi farlo facendo:SELECT @names = @names + ISNULL(' ' + Name, '')
Vita1ij

28

È stata suggerita una soluzione CTE ricorsiva, ma non è stato fornito alcun codice. Il codice seguente è un esempio di CTE ricorsivo. Nota che sebbene i risultati corrispondano alla domanda, i dati non corrispondono esattamente alla descrizione fornita, dato che presumo che tu voglia davvero farlo su gruppi di righe, non su tutte le righe della tabella. La modifica in modo che corrisponda a tutte le righe della tabella viene lasciata come esercizio per il lettore.

;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

1
Per i sbalorditi: questa query inserisce 12 righe (3 colonne) in un riferimento temporaneo, quindi crea un'espressione di tabella comune ricorsiva (rCTE) e quindi appiattisce la name colonna in una stringa separata da virgole per 4 gruppi di ids. A prima vista, penso che questo sia più lavoro di quello che fanno la maggior parte delle altre soluzioni per SQL Server.
anno

2
@knb: non sono sicuro che sia lode, condanna o sorpresa. La tabella di base è perché mi piace che i miei esempi funzionino davvero, non ha nulla a che fare con la domanda.
jmoreno,

26

A partire da PostgreSQL 9.0 questo è abbastanza semplice:

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

Nelle versioni precedenti alla 9.0 array_agg()può essere usato come mostrato da hgmnz


Per fare ciò con colonne che non sono di tipo testo, è necessario aggiungere un cast di tipo:SELECT string_agg(non_text_type::text, ',') FROM table
Torben Kohlmeier

@TorbenKohlmeier: è necessario solo per colonne senza caratteri (ad es. Intero, decimale). Funziona bene per varcharochar
a_horse_with_no_name

26

Devi creare una variabile che conterrà il tuo risultato finale e selezionarla, in questo modo.

La soluzione più semplice

DECLARE @char VARCHAR(MAX);

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

PRINT @char;


18

L'uso di XML mi ha aiutato a separare le righe con le virgole. Per la virgola aggiuntiva possiamo usare la funzione di sostituzione di SQL Server. Invece di aggiungere una virgola, l'uso dell'AS 'data ()' concatenerà le righe con spazi, che in seguito possono essere sostituiti da virgole come sintassi scritta di seguito.

REPLACE(
        (select FName AS 'data()'  from NameList  for xml path(''))
         , ' ', ', ') 

2
Questa è la migliore risposta qui a mio parere. L'uso di declare variabile non è utile quando è necessario unirsi in un'altra tabella, e questo è bello e breve. Buon lavoro.
David Roussel,

7
non funziona bene se i dati di FName hanno già spazi, ad esempio "Il mio nome"
binball

Funziona davvero per me su ms-sql 2016 Seleziona REPLACE ((seleziona Nome AS 'data ()' da Brand Where Id IN (1,2,3,4) per percorso xml ('')), '', ' , ") come allBrands
Rejwanul Reja,

17

Una soluzione pronta per l'uso, senza virgole aggiuntive:

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

Un elenco vuoto comporterà un valore NULL. Di solito inserirai l'elenco in una colonna di tabella o variabile di programma: regola la lunghezza massima di 255 in base alle tue necessità.

(Diwakar e Jens Frandsen hanno fornito buone risposte, ma hanno bisogno di miglioramenti.)


C'è uno spazio prima della virgola quando si utilizza questo :(
slayernoah

1
Sostituisci semplicemente ', 'con ','se non vuoi lo spazio extra.
Daniel Reis,

13
SELECT STUFF((SELECT ', ' + name FROM [table] FOR XML PATH('')), 1, 2, '')

Ecco un esempio:

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

10
DECLARE @Names VARCHAR(8000)
SELECT @name = ''
SELECT @Names = @Names + ',' + Names FROM People
SELECT SUBSTRING(2, @Names, 7998)

Questo mette la virgola vagante all'inizio.

Tuttavia, se hai bisogno di altre colonne o di CSV di una tabella figlio, devi racchiuderla in un campo scalare definito dall'utente (UDF).

Puoi utilizzare il percorso XML come sottoquery correlata anche nella clausola SELECT (ma dovrei aspettare fino a quando non torno a lavorare perché Google non fa cose di lavoro a casa :-)


10

Con le altre risposte, la persona che legge la risposta deve essere a conoscenza di una tabella di dominio specifica come veicolo o studente. La tabella deve essere creata e popolata con i dati per testare una soluzione.

Di seguito è riportato un esempio che utilizza la tabella "Information_Schema.Columns" di SQL Server. Utilizzando questa soluzione, non è necessario creare tabelle o aggiungere dati. In questo esempio viene creato un elenco separato da virgole di nomi di colonna per tutte le tabelle nel database.

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 

7

Per i DB Oracle, vedi questa domanda: Come si possono concatenare più righe in una in Oracle senza creare una procedura memorizzata?

La risposta migliore sembra essere di @Emmanuel, usando la funzione LISTAGG () integrata, disponibile in Oracle 11g versione 2 e successive.

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

come sottolineato da @utente762952, e secondo la documentazione di Oracle http://www.oracle-base.com/articles/misc/string-aggregation-techniques.php , anche la funzione WM_CONCAT () è un'opzione. Sembra stabile, ma Oracle sconsiglia esplicitamente di usarlo per qualsiasi applicazione SQL, quindi usalo a tuo rischio.

A parte questo, dovrai scrivere la tua funzione; il documento Oracle sopra ha una guida su come farlo.


7

Per evitare valori null è possibile utilizzare CONCAT ()

DECLARE @names VARCHAR(500)
SELECT @names = CONCAT(@names, ' ', name) 
FROM Names
select @names

Sarebbe bello sapere perché CONCAT funziona. Un collegamento a MSDN sarebbe carino.
Ingegnere invertito,

7

Mi è piaciuta molto l'eleganza della risposta di Dana . Volevo solo completarlo.

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

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

-- Deleting last two symbols (', ')
SET @sSql = LEFT(@sSql, LEN(@sSql) - 1)

Se stai eliminando gli ultimi due simboli ",", devi aggiungere "," dopo Nome ("SELECT \ @names = \ @names + Name +", "FROM Names"). In questo modo gli ultimi due caratteri saranno sempre ",".
JT_

Nel mio caso avevo bisogno di sbarazzarsi del leader comma in modo da modificare la query per SELECT @names = @names + CASE WHEN LEN(@names)=0 THEN '' ELSE ', ' END + Name FROM Namesallora non devi troncare in seguito.
Tian van Heerden

6

Questa risposta richiederà alcuni privilegi nel server per funzionare.

Le assemblee sono una buona opzione per te. Ci sono molti siti che spiegano come crearlo. Quello per me è molto ben spiegato è questo uno

Se lo desideri, ho già creato l'assembly ed è possibile scaricare qui la DLL .

Dopo averlo scaricato, dovrai eseguire il seguente script nel tuo SQL Server:

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

Osservare che il percorso dell'assemblaggio potrebbe essere accessibile al server. Dato che hai completato con successo tutti i passaggi, puoi utilizzare la funzione come:

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

Spero che sia d'aiuto!!!


1
Il collegamento DLL è un errore 404. L'uso di un assembly per questo è eccessivo. Vedi la migliore risposta per SQL Server.
Protiguous

6

Esempio completo di MySQL:

Abbiamo utenti che possono avere molti dati e vogliamo avere un output, in cui possiamo vedere tutti i dati degli utenti in un elenco:

Risultato:

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

Impostazione tabella:

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);

Query:

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

5

Di solito uso select in questo modo per concatenare le stringhe in SQL Server:

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

5

Se vuoi gestire i null puoi farlo aggiungendo una clausola where o aggiungendo un'altra COALESCE attorno alla prima.

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

5

Questo ha funzionato per me ( SqlServer 2016 ):

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

Ecco la fonte: https://www.mytecbits.com/

E una soluzione per MySql (poiché questa pagina viene visualizzata in Google per MySql)

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

Dalla documentazione di MySql



4

Anche questo può essere utile

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

ritorna

Peter,Paul,Mary

5
Purtroppo questo comportamento sembra non essere ufficialmente supportato. MSDN dice: "Se si fa riferimento a una variabile in un elenco di selezione, dovrebbe essere assegnato un valore scalare o l'istruzione SELECT dovrebbe restituire solo una riga." E ci sono persone che hanno riscontrato problemi: sqlmag.com/sql-server/multi-row-variable-assignment-and-order
blueling
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.