Considérez une table de base de données contenant des noms, avec trois rangées :
Peter
Paul
Mary
Existe-t-il un moyen simple de transformer cela en une seule chaîne de caractères Peter, Paul, Mary
?
Considérez une table de base de données contenant des noms, avec trois rangées :
Peter
Paul
Mary
Existe-t-il un moyen simple de transformer cela en une seule chaîne de caractères Peter, Paul, Mary
?
Si vous êtes sur SQL Server 2017 ou Azure, voir la réponse de Mathieu Renda.
J'ai rencontré un problème similaire lorsque j'essayais de joindre deux tables avec des relations de un à plusieurs. En SQL 2005, j'ai trouvé que la méthode XML PATH
peut gérer très facilement la concaténation des lignes.
S'il y a une table appelée STUDENTS
SubjectID StudentName
---------- -------------
1 Mary
1 John
1 Sam
2 Alaina
2 Edward
Le résultat attendu était:
SubjectID StudentName
---------- -------------
1 Mary, John, Sam
2 Alaina, Edward
J'ai utilisé le T-SQL
suivant:
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 (''), TYPE
).value('text()[1]','nvarchar(max)') [Students]
FROM dbo.Students ST2
) [Main]
Vous pouvez faire la même chose de manière plus compacte si vous pouvez concaténer les virgules au début et utiliser substring
pour sauter la première afin de ne pas avoir besoin de faire une sous-requête:
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 (''), TYPE
).value('text()[1]','nvarchar(max)'), 2, 1000) [Students]
FROM dbo.Students ST2
Je reçois une erreur "Syntaxe incorrecte près du mot clé 'For'" en exécutant MS SQL Server 2008 R2
Grande solution. Ce qui suit peut être utile si vous avez besoin de manipuler des caractères spéciaux comme ceux en HTML: Rob Farley: Handling special characters with FOR XML PATH('').
Cette réponse peut retourner des résultats inattendus. Pour des résultats cohérents, utilisez l'une des méthodes FOR XML PATH détaillées dans d'autres réponses.
Utilisez COALESCE
:
DECLARE @Names VARCHAR(8000)
SELECT @Names = COALESCE(@Names + ', ', '') + Name
FROM People
Juste une explication (puisque cette réponse semble être régulièrement consultée) :
1) Pas besoin d'initialiser @Names
avec une valeur de chaîne vide.
2) Pas besoin de retirer un séparateur supplémentaire à la fin.
La solution ci-dessus donnera des résultats incorrects si une ligne a une valeur de nom NULL (si un NULL est rencontré, le NULL rendra la variable @Names
NULL après cette ligne, et la ligne suivante recommencera avec une chaîne vide à nouveau. Facilement corrigé avec l'une des deux solutions :
DECLARE @Names VARCHAR(8000) SELECT @Names = COALESCE(@Names + ', ', '') + Name FROM People WHERE Name IS NOT NULL
ou :
DECLARE @Names VARCHAR(8000)
SELECT @Names = COALESCE(@Names + ', ', '') +
ISNULL(Name, 'N/A')
FROM People
En fonction du comportement souhaité (la première option filtre simplement les NULL, la deuxième option les conserve dans la liste avec un message de marque [remplacez 'N/A' par ce qui est approprié pour vous]).
Pour être clair, coalesce n'a rien à voir avec la création de la liste, il garantit simplement que les valeurs NULL ne sont pas incluses.
@Graeme Perrow Cela n'exclut pas les valeurs NULL (un WHERE est nécessaire pour cela -- cela perdre des résultats si l'une des valeurs d'entrée est NULL), et c'est nécessaire dans cette approche car : NULL + non-NULL -> NULL et non-NULL + NULL -> NULL; aussi @Name est NULL par défaut et, en fait, cette propriété est utilisée comme un sentinelle implicite ici pour déterminer si une ', ' doit être ajoutée ou non.
Deux façons de résoudre ce problème pour ignorer gracieusement les valeurs NULL: Soit SELECT @Names = @Names + ', ' + Name FROM People WHERE Name IS NOT NULL
ou bien SELECT @Names = COALESCE(@Names + ', ' + Name, @Names) FROM People
.
Une méthode non encore montrée via la commande XML
data()
dans SQL Server est :
Supposons une table appelée NameList avec une colonne appelée FName,
SELECT FName + ', ' AS 'data()'
FROM NameList
FOR XML PATH('')
retourne :
"Peter, Paul, Mary, "
Seule la virgule supplémentaire doit être traitée.
Tel qu'adopté du commentaire de @NReilingh, vous pouvez utiliser la méthode suivante pour supprimer la virgule finale. En supposant les mêmes noms de table et de colonne :
STUFF(REPLACE((SELECT '#!' + LTRIM(RTRIM(FName)) AS 'data()' FROM NameList
FOR XML PATH('')),' #!',', '), 1, 2, '') as Brands
Oh mon dieu, c'est incroyable! Lorsqu'il est exécuté seul, comme dans votre exemple, le résultat est formaté comme un hyperlien qui, lorsqu'il est cliqué (dans SSMS), ouvre une nouvelle fenêtre contenant les données, mais lorsqu'il est utilisé dans une requête plus large, il apparaît simplement comme une chaîne de caractères. Est-ce une chaîne de caractères? ou est-ce du XML que je dois traiter différemment dans l'application qui utilisera ces données?
Cette approche échappe également aux caractères XML tels que < et >. Donc, en sélectionnant '< b >' + FName + '' donne "& lt; b & gt; John & lt; / b & gt; & lt; b & gt; Paul ..."
Solution soignée. Je remarque que même lorsque je n'ajoute pas le + ', '
, il ajoute quand même un espace simple entre chaque élément concaténé.
SELECT Stuff(
(SELECT N', ' + Name FROM Names FOR XML PATH(''),TYPE)
.value('text()[1]','nvarchar(max)'),1,2,N'')
vous pouvez utiliser la syntaxe FOR JSON
par exemple.
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
Et le résultat sera
Id Emails
1 abc@gmail.com
2 NULL
3 def@gmail.com, xyz@gmail.com
Ceci fonctionnera même si vos données contiennent des caractères XML invalides
le '"},{"_":"'
est sécurisé car si vos données contiennent '"},{"_":"',
cela sera échappé en "},{\"_\":\"
Vous pouvez remplacer ', '
par n'importe quel séparateur de chaîne
Vous pouvez utiliser la nouvelle fonction STRING_AGG
J'aime le mieux cette solution, car je peux facilement l'utiliser dans une liste déroulante en ajoutant 'comme '. Je ne suis pas sûr comment faire cela avec la solution de @Ritesh.
Dans MySQL, il existe une fonction, GROUP_CONCAT(), qui vous permet de concaténer les valeurs de plusieurs lignes. Exemple :
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
Fonctionne essentiellement. Deux choses à considérer : 1) si votre colonne n'est pas un CHAR
, vous devez la caster, par exemple via GROUP_CONCAT( CAST(id AS CHAR(8)) ORDER BY id ASC SEPARATOR ',')
2) si vous avez de nombreuses valeurs qui arrivent, vous devriez augmenter la group_concat_max_len
comme écrit dans stackoverflow.com/a/1278210/1498405
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.
27 votes
Pour des réponses spécifiques à SQL Server, essayez cette question.
20 votes
Pour MySQL, consultez Group_Concat à partir de cette réponse
28 votes
Je souhaite que la prochaine version de SQL Server offre une nouvelle fonctionnalité pour résoudre élégamment la concaténation de chaînes multi-rangées sans la bêtise de FOR XML PATH.
0 votes
Étape par étape tutoriel pour décrire les réponses ci-dessus : essayez cet article : [ sqlmatters.com/Articles/… ]
4 votes
Pas SQL, mais si c'est une chose ponctuelle, vous pouvez coller la liste dans cet outil de navigateur convert.town/column-to-comma-separated-list
3 votes
Dans Oracle, vous pouvez utiliser la fonction LISTAGG(COLUMN_NAME) à partir de la version 11g r2, avant cela il existe une fonction non supportée appelée WM_CONCAT(COLUMN_NAME) qui fait la même chose.
0 votes
Cette solution CLR qui peut être branchée directement est quelque chose de similaire à mon SQL GROUP_CONCAT, ici
0 votes
Vous pouvez utiliser la fonction de concaténation de chaînes. Je ne peux pas ajouter de réponse (car elle est verrouillée), donc j'ajoute la réponse ici :
DECLARE @big_string varchar(max) = ''; SELECT @big_string += x.s + ',' FROM (VALUES ('string1'), ('string2'), ('string3')) AS x(s);
. Maintenant, affichez le résultat :SELECT @big_string;
. C'est aussi simple.0 votes
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]