web-dev-qa-db-fra.com

Convertir plusieurs lignes en une seule avec une virgule comme séparateur

Si je publie SELECT username FROM Users J’obtiens ce résultat:

 nom d'utilisateur 
 -------- 
 Paul 
 John 
 Mary 

mais ce dont j'ai vraiment besoin, c'est n rangée avec toutes les valeurs séparées par une virgule, comme ceci:

 Paul, John, Mary 

Comment puis-je faire cela?

70
Pavel Bastov

Cela devrait fonctionner pour vous. Testé depuis le début jusqu'à SQL 2000.

create table #user (username varchar(25))

insert into #user (username) values ('Paul')
insert into #user (username) values ('John')
insert into #user (username) values ('Mary')

declare @tmp varchar(250)
SET @tmp = ''
select @tmp = @tmp + username + ', ' from #user

select SUBSTRING(@tmp, 0, LEN(@tmp))
84
mwigdahl
 select
   distinct  
    stuff((
        select ',' + u.username
        from users u
        where u.username = username
        order by u.username
        for xml path('')
    ),1,1,'') as userlist
from users
group by username

eu une faute de frappe avant, les travaux ci-dessus

106
Hogan

bonne revue de plusieurs approches:

http://blogs.msmvps.com/robfarley/2007/04/07/coalesce-is-not-the-answer-to-string-concatentation-in-t-sql/

Copie de l'article -

Coalesce n'est pas la solution à la concaténation de chaînes dans T-SQL Au cours des années, j'ai lu de nombreux articles sur l'utilisation de la fonction COALESCE pour que la concaténation de chaînes fonctionne dans T-SQL. C’est l’un des exemples ici (emprunté à Readifarian Marc Ridey).

DECLARE @categories varchar(200)
SET @categories = NULL

SELECT @categories = COALESCE(@categories + ',','') + Name
FROM Production.ProductCategory

SELECT @categories

Cette requête peut être assez efficace, mais il faut faire attention et utiliser COALESCE correctement. COALESCE est la version de ISNULL qui peut prendre plus de deux paramètres. Il retourne la première chose dans la liste des paramètres qui n'est pas nulle. Donc, en réalité, cela n'a rien à voir avec la concaténation et le code suivant est exactement le même, sans utiliser COALESCE:

DECLARE @categories varchar(200)
SET @categories = ''

SELECT @categories = @categories + ',' + Name
FROM Production.ProductCategory

SELECT @categories

Mais la nature non ordonnée des bases de données rend cela peu fiable. Si T-SQL n’a pas (encore) de fonction de concaténation, c’est qu’il s’agit d’un agrégat pour lequel l’ordre des éléments est important. En utilisant cette méthode de concaténation de chaînes par affectation de variable, vous pouvez réellement constater que la réponse renvoyée ne contient pas toutes les valeurs, en particulier si vous souhaitez que les sous-chaînes soient placées dans un ordre particulier. Considérez ce qui suit, qui sur ma machine ne retourne que ', Accessoires', quand je voulais le retourner ', Vélos, Vêtements, Composants, Accessoires':

DECLARE @categories varchar(200)
SET @categories = NULL

SELECT @categories = COALESCE(@categories + ',','') + Name
FROM Production.ProductCategory
ORDER BY LEN(Name)

SELECT @categories

Mieux vaut utiliser une méthode qui prend en compte l’ordre et qui a été incluse dans SQL2005 spécifiquement dans le but de la concaténation de chaînes - FOR XML PATH ('')

SELECT ',' + Name
FROM Production.ProductCategory
ORDER BY LEN(Name)
FOR XML PATH('') 

Dans le post que j'ai fait récemment en comparant GROUP BY et DISTINCT lors de l'utilisation de sous-requêtes, j'ai montré l'utilisation de FOR XML PATH (''). Examinez cela et vous verrez comment cela fonctionne dans une sous-requête. La fonction 'STUFF' sert uniquement à supprimer la virgule.

USE tempdb;
GO
CREATE TABLE t1 (id INT, NAME VARCHAR(MAX));
INSERT t1 values (1,'Jamie');
INSERT t1 values (1,'Joe');
INSERT t1 values (1,'John');
INSERT t1 values (2,'Sai');
INSERT t1 values (2,'Sam');
GO

select
    id,
    stuff((
        select ',' + t.[name]
        from t1 t
        where t.id = t1.id
        order by t.[name]
        for xml path('')
    ),1,1,'') as name_csv
from t1
group by id
; 

FOR XML PATH est l’une des seules situations dans lesquelles vous pouvez utiliser ORDER BY dans une sous-requête. L'autre est TOP. Et lorsque vous utilisez une colonne sans nom et FOR XML PATH (''), vous obtenez une concaténation directe, sans balise XML. Cela signifie que les chaînes seront codées au format HTML. Par conséquent, si vous concaténez des chaînes pouvant contenir le caractère <(etc), vous devriez peut-être résoudre ce problème ultérieurement, mais dans les deux cas, il s'agit toujours du meilleur moyen de concaténer des chaînes. dans SQL Server 2005.

44
A-K

construire sur mwigdahls répondre. si vous avez également besoin de regrouper, voici comment l'obtenir

group, csv
'group1', 'paul, john'
'group2', 'mary'

    --drop table #user
create table #user (groupName varchar(25), username varchar(25))

insert into #user (groupname, username) values ('apostles', 'Paul')
insert into #user (groupname, username) values ('apostles', 'John')
insert into #user (groupname, username) values ('family','Mary')


select
    g1.groupname
    , stuff((
        select ', ' + g.username
        from #user g        
        where g.groupName = g1.groupname        
        order by g.username
        for xml path('')
    ),1,2,'') as name_csv
from #user g1
group by g1.groupname
10
Tom McDonald

Vous pouvez utiliser cette requête pour effectuer la tâche ci-dessus:

DECLARE @test NVARCHAR(max)  
SELECT @test = COALESCE(@test + ',', '') + field2 FROM #test
SELECT field2 = @test 

Pour plus de détails et une explication pas à pas, visitez le lien suivant http://oops-solution.blogspot.com/2011/11/sql-server-convert-table-column-data.html

6
Rashmi Kant
DECLARE @EmployeeList varchar(100)

SELECT @EmployeeList = COALESCE(@EmployeeList + ', ', '') + 
   CAST(Emp_UniqueID AS varchar(5))
FROM SalesCallsEmployees
WHERE SalCal_UniqueID = 1

SELECT @EmployeeList

source: http://www.sqlteam.com/article/using-coalesce-to-build-comma-delimited-string

6
vinay

En SQLite, c'est plus simple. Je pense qu'il existe des implémentations similaires pour MySQL, MSSql et Orable

CREATE TABLE Beatles (id integer, name string );
INSERT INTO Beatles VALUES (1, "Paul");
INSERT INTO Beatles VALUES (2, "John");
INSERT INTO Beatles VALUES (3, "Ringo");
INSERT INTO Beatles VALUES (4, "George");
SELECT GROUP_CONCAT(name, ',') FROM Beatles;
5
elcuco

Une solution propre et flexible dans MS SQL Server 2005/2008 consiste à créer une fonction d'agrégation CLR.

Vous trouverez plusieurs articles (avec code) sur google .

Cela ressemble à cet article vous guide tout au long du processus en utilisant C #.

3
Arjan Einbu

vous pouvez utiliser stuff () pour convertir les lignes en valeurs séparées par des virgules

select
EmployeeID,
stuff((
  SELECT ',' + FPProjectMaster.GroupName 
      FROM     FPProjectInfo AS t INNER JOIN
              FPProjectMaster ON t.ProjectID = FPProjectMaster.ProjectID
      WHERE  (t.EmployeeID = FPProjectInfo.EmployeeID)
              And t.STatusID = 1
              ORDER BY t.ProjectID
       for xml path('')
       ),1,1,'') as name_csv
from FPProjectInfo
group by EmployeeID;

Merci @AlexKuznetsov pour la référence pour obtenir cette réponse.

2
Ram