web-dev-qa-db-fra.com

Comment concaténer du texte de plusieurs lignes en une seule chaîne de texte dans SQL Server?

Considérons une table de base de données contenant des noms, avec trois lignes:

Peter
Paul
Mary

Existe-t-il un moyen simple de transformer cela en une seule chaîne de Peter, Paul, Mary?

1766
JohnnyM

Si vous êtes sur SQL Server 2017 ou Azure, voir réponse de Mathieu Renda .

J'avais un problème similaire lorsque j'essayais de joindre deux tables avec des relations un à plusieurs. En SQL 2005, j’ai constaté 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 que j'attendais é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 ('')
            ) [Students]
        FROM dbo.Students ST2
    ) [Main]

Vous pouvez faire la même chose d'une manière plus compacte si vous pouvez concattre les virgules au début et utiliser substring pour ignorer la première, de sorte que vous n'avez pas 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 ('')
        ), 2, 1000) [Students]
FROM dbo.Students ST2
1315
Ritesh

Cette réponse peut renvoyer résultats inattendus Pour obtenir des résultats cohérents, utilisez l'une des méthodes FOR XML PATH décrites 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 avoir des vues relativement régulières):

  • La coalesce est vraiment juste une astuce utile qui accomplit deux choses:

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 un NULL nom valeur (s'il y a un NULL, le NULL fera @NamesNULL après cette ligne, et la ligne suivante recommencera comme une chaîne vide à nouveau. Facilement réparable avec l’une des deux solutions suivantes:
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 ne filtre que NULL), la deuxième option les conserve dans la liste avec un message de marqueur [remplacez "N/A" par tout ce qui est approprié pour vous]).

965
Chris Shaffer

Une méthode non encore affichée via la commande XMLdata() dans MS SQL Server est la suivante:

Suppose la table appelée NameList avec une colonne appelée FName,

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

résultats:

"Peter, Paul, Mary, "

Seule la virgule supplémentaire doit être traitée.

Edit: Comme adopté dans le commentaire de @ NReilingh, vous pouvez utiliser la méthode suivante pour supprimer la virgule de fin. 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
338
jens frandsen

SQL Server 2017+ et SQL Azure: STRING_AGG

À partir de la prochaine version de SQL Server, nous pouvons enfin concaténer des lignes sans avoir à recourir à une variable ou à une sorcellerie XML.

STRING_AGG (Transact-SQL)

sans regroupement

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

Avec regroupement:

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

avec regroupement et sous-tri

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

Dans SQL Server 2005

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

Dans SQL Server 2016

vous pouvez utiliser le FOR JSON syntaxe

c'est à 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

Et le résultat deviendra

Id  Emails
1   [email protected]
2   NULL
3   [email protected], [email protected]

Cela fonctionnera même si vos données contiennent des caractères XML non valides.

le '"},{"_":"' est sécurisé, car si vos données contiennent '"},{"_":"',, il sera échappé à "},{\"_\":\"

Vous pouvez remplacer ', ' par tout séparateur de chaîne


Et dans SQL Server 2017, la base de données Azure SQL

Vous pouvez utiliser le nouveau fonction STRING_AGG

277
Steven Chong

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
112
Darryl Hein

Utilisez COALESCE - En savoir plus à partir d'ici

Par exemple:

102

103

104

Ensuite, écrivez ci-dessous le code dans le serveur 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

La sortie serait:

102,103,104
55
pedram

Les tableaux Postgres sont géniaux. Exemple:

Créer des données de 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)

Les regrouper dans un tableau:

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

Convertissez le tableau en chaîne délimitée par des virgules:

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

TERMINÉ

Depuis PostgreSQL 9.0, il est encore plus facile .

47
hgmnz

Oracle 11g version 2 prend en charge la fonction LISTAGG. Documentation ici .

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.

Attention

Soyez prudent lors de l'implémentation de cette fonction s'il est possible que la chaîne résultante dépasse 4 000 caractères. Il va lancer une exception. Si tel est le cas, vous devez gérer l'exception ou lancer votre propre fonction qui empêche la chaîne jointe de dépasser 4 000 caractères.

45
Alex

Dans SQL Server 2005 et versions ultérieures, utilisez la requête ci-dessous pour concaténer les lignes.

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
33
Yogesh Bhadauirya

Je n’ai pas accès à un serveur SQL à la maison, alors je suppose que la syntaxe est la suivante, mais c’est plus ou moins:

DECLARE @names VARCHAR(500)

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

Vous devez créer une variable qui contiendra votre résultat final et la sélectionnera comme ceci.

La solution la plus simple

DECLARE @char VARCHAR(MAX);

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

PRINT @char;
25
Tigerjz32

Une solution CTE récursive a été suggérée, mais aucun code n'a été fourni. Le code ci-dessous est un exemple de CTE récursif. Notez que, bien que les résultats correspondent à la question, les données ne correspondent pas tout à fait à la description donnée, car je suppose que vous voulez vraiment le faire sur des groupes de lignes, pas sur toutes les lignes de la table. Le changer pour qu'il corresponde à toutes les lignes du tableau reste un exercice pour le lecteur.

;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
25
jmoreno

À partir de PostgreSQL 9.0, ceci est assez simple:

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

Dans les versions antérieures à 9.0, array_agg() peut être utilisé comme indiqué par hgmnz.

23

Dans SQL Server vNext, cette fonction sera intégrée à la fonction STRING_AGG. Pour en savoir plus, cliquez ici: https://msdn.Microsoft.com/en-us/library/mt790580.aspx

21
Henrik Fransas

Utiliser XML m'a aidé à obtenir des lignes séparées par des virgules. Pour la virgule supplémentaire, nous pouvons utiliser la fonction de remplacement de SQL Server. Au lieu d'ajouter une virgule, l'utilisation de l'AS 'data ()' concaténera les lignes avec des espaces, qui pourront être remplacés ultérieurement par des virgules, comme indiqué ci-dessous.

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

Une solution prête à l'emploi, sans virgule supplémentaire:

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

Une liste vide entraînera une valeur NULL. Habituellement, vous insérez la liste dans une colonne de table ou une variable de programme: ajustez la longueur maximale de 255 à vos besoins.

(Diwakar et Jens Frandsen ont fourni de bonnes réponses, mais doivent être améliorées.)

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

Voici un exemple:

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
12
Max Szczurek
DECLARE @Names VARCHAR(8000)
SELECT @name = ''
SELECT @Names = @Names + ',' + Names FROM People
SELECT SUBSTRING(2, @Names, 7998)

Cela met la virgule parasite au début.

Toutefois, si vous avez besoin d'autres colonnes, ou pour créer une table enfant au format CSV, vous devez envelopper cette opération dans un champ défini par l'utilisateur scalaire (UDF).

Vous pouvez également utiliser le chemin XML en tant que sous-requête corrélée dans la clause SELECT (mais je devrai attendre jusqu'à ce que je retourne au travail car Google ne fonctionne pas à la maison :-)

10
gbn

Avec les autres réponses, la personne qui lit la réponse doit connaître un tableau de domaine spécifique, tel que véhicule ou élève. La table doit être créée et renseignée avec des données pour tester une solution.

Vous trouverez ci-dessous un exemple d'utilisation de la table "Information_Schema.Columns" de SQL Server. En utilisant cette solution, il n'est pas nécessaire de créer de tables ni d'ajouter de données. Cet exemple crée une liste de noms de colonnes séparés par des virgules pour toutes les tables de la base de données.

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 

Pour les bases de données Oracle, consultez la question suivante: Comment concaténer plusieurs lignes en une ligne dans Oracle sans créer de procédure stockée?

La meilleure réponse semble être celle de @Emmanuel, à l'aide de la fonction intégrée LISTAGG (), disponible dans Oracle 11g version 2 et ultérieure.

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

comme @ user762952 l’a fait remarquer, et selon la documentation d’Oracle http://www.Oracle-base.com/articles/misc/string-aggregation-techniques.php , la fonction WM_CONCAT () est également une fonction option. Cela semble stable, mais Oracle recommande explicitement de ne pas l'utiliser pour toute application SQL, utilisez-le donc à vos risques et périls.

Autre que cela, vous devrez écrire votre propre fonction; Le document Oracle ci-dessus contient un guide expliquant comment procéder.

7
ZeroK

J'ai vraiment aimé l'élégance de réponse de Dana . Je voulais juste le rendre complet.

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

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

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

Pour éviter les valeurs NULL, vous pouvez utiliser CONCAT ()

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

Cette réponse nécessitera certains privilèges sur le serveur pour fonctionner.

Assemblies sont une bonne option pour vous. Il y a beaucoup de sites qui expliquent comment le créer. Celui que je pense est très bien expliqué est ceci n

Si vous le souhaitez, j'ai déjà créé l'assembly et il est possible de télécharger le fichier DLL ici .

Une fois que vous l'avez téléchargé, vous devrez exécuter le script suivant sur votre serveur 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

Observez que le chemin d'accès à Assembly peut être accessible au serveur. Comme vous avez réussi toutes les étapes, vous pouvez utiliser la fonction comme:

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

J'espère que ça aide!!!

6
Nizam

J'utilise habituellement select comme ceci pour concaténer des chaînes dans 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

Exemple complet avec MySQL:

Nous avons des utilisateurs qui peuvent avoir plusieurs données et nous voulons une sortie, où nous pouvons voir toutes les données des utilisateurs dans une liste:

Résultat:

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

Configuration de la table:

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

Requête:

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
user1767754

Si vous souhaitez traiter les valeurs null, vous pouvez le faire en ajoutant une clause where ou en ajoutant une autre COALESCE autour de la première.

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

Cela peut être utile aussi

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

résultats

Peter,Paul,Mary
4
endo64

Dans Oracle, il s'agit de wm_concat. Je crois que cette fonction est disponible dans la version version 10g et supérieure.

4
user762952

Cette méthode s'applique à la base de données Teradata Aster uniquement dans la mesure où elle utilise sa fonction NPATH.

Encore une fois, nous avons des étudiants de table

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

Ensuite, avec NPATH, il n’ya qu’un simple SELECT:

SELECT * FROM npath(
  ON Students
  PARTITION BY SubjectID
  ORDER BY StudentName
  MODE(nonoverlapping)
  PATTERN('A*')
  SYMBOLS(
    'true' as A
  )
  RESULT(
    FIRST(SubjectID of A) as SubjectID,
    ACCUMULATE(StudentName of A) as StudentName
  )
);

Résultat:

SubjectID       StudentName
----------      -------------
1               [John, Mary, Sam]
2               [Alaina, Edward]
3
topchef

Ce n’est pas que j’ai fait d’analyse de la performance, car ma liste comptait moins de 10 éléments, mais j’ai été étonné d’avoir parcouru une trentaine de réponses étranges. Il n'est même pas nécessaire de définir ma variable (la valeur par défaut est NULL de toute façon) et cela suppose que toutes les entrées de la table de données source ne sont pas vides:

DECLARE @MyList VARCHAR(1000), @Delimiter CHAR(2) = ', '
SELECT @MyList = CASE WHEN @MyList > '' THEN @MyList + @Delimiter ELSE '' END + FieldToConcatenate FROM MyData

Je suis sûr que COALESCE utilise en interne la même idée. Espérons que MS ne changera pas cela pour moi.

3
Glen

Voici la solution complète pour y parvenir:

-- Table Creation
CREATE TABLE Tbl
( CustomerCode    VARCHAR(50)
, CustomerName    VARCHAR(50)
, Type VARCHAR(50)
,Items    VARCHAR(50)
)

insert into Tbl
SELECT 'C0001','Thomas','BREAKFAST','Milk'
union SELECT 'C0001','Thomas','BREAKFAST','Bread'
union SELECT 'C0001','Thomas','BREAKFAST','Egg'
union SELECT 'C0001','Thomas','LUNCH','Rice'
union SELECT 'C0001','Thomas','LUNCH','Fish Curry'
union SELECT 'C0001','Thomas','LUNCH','Lessy'
union SELECT 'C0002','JOSEPH','BREAKFAST','Bread'
union SELECT 'C0002','JOSEPH','BREAKFAST','Jam'
union SELECT 'C0002','JOSEPH','BREAKFAST','Tea'
union SELECT 'C0002','JOSEPH','Supper','Tea'
union SELECT 'C0002','JOSEPH','Brunch','Roti'

-- function creation
GO
CREATE  FUNCTION [dbo].[fn_GetItemsByType]
(   
    @CustomerCode VARCHAR(50)
    ,@Type VARCHAR(50)
)
RETURNS @ItemType TABLE  ( Items VARCHAR(5000) )
AS
BEGIN

        INSERT INTO @ItemType(Items)
    SELECT  STUFF((SELECT distinct ',' + [Items]
         FROM Tbl 
         WHERE CustomerCode = @CustomerCode
            AND Type=@Type
            FOR XML PATH(''))
        ,1,1,'') as  Items



    RETURN 
END

GO

-- fianl Query
DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(Type) 
                    from Tbl
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT CustomerCode,CustomerName,' + @cols + '
             from 
             (
                select  
                    distinct CustomerCode
                    ,CustomerName
                    ,Type
                    ,F.Items
                    FROM Tbl T
                    CROSS APPLY [fn_GetItemsByType] (T.CustomerCode,T.Type) F
            ) x
            pivot 
            (
                max(Items)
                for Type in (' + @cols + ')
            ) p '

execute(@query) 
3
Ravi Pipaliya

--SQL Server 2005+

CREATE TABLE dbo.Students
(
    StudentId INT
    , Name VARCHAR(50)
    , CONSTRAINT PK_Students PRIMARY KEY (StudentId)
);

CREATE TABLE dbo.Subjects
(
    SubjectId INT
    , Name VARCHAR(50)
    , CONSTRAINT PK_Subjects PRIMARY KEY (SubjectId)
);

CREATE TABLE dbo.Schedules
(
    StudentId INT
    , SubjectId INT
    , CONSTRAINT PK__Schedule PRIMARY KEY (StudentId, SubjectId)
    , CONSTRAINT FK_Schedule_Students FOREIGN KEY (StudentId) REFERENCES dbo.Students (StudentId)
    , CONSTRAINT FK_Schedule_Subjects FOREIGN KEY (SubjectId) REFERENCES dbo.Subjects (SubjectId)
);

INSERT dbo.Students (StudentId, Name) VALUES
    (1, 'Mary')
    , (2, 'John')
    , (3, 'Sam')
    , (4, 'Alaina')
    , (5, 'Edward')
;

INSERT dbo.Subjects (SubjectId, Name) VALUES
    (1, 'Physics')
    , (2, 'Geography')
    , (3, 'French')
    , (4, 'Gymnastics')
;

INSERT dbo.Schedules (StudentId, SubjectId) VALUES
    (1, 1)      --Mary, Physics
    , (2, 1)    --John, Physics
    , (3, 1)    --Sam, Physics
    , (4, 2)    --Alaina, Geography
    , (5, 2)    --Edward, Geography
;

SELECT 
    sub.SubjectId
    , sub.Name AS [SubjectName]
    , ISNULL( x.Students, '') AS Students
FROM
    dbo.Subjects sub
    OUTER APPLY
    (
        SELECT 
            CASE ROW_NUMBER() OVER (ORDER BY stu.Name) WHEN 1 THEN '' ELSE ', ' END
            + stu.Name
        FROM
            dbo.Students stu
            INNER JOIN dbo.Schedules sch
                ON stu.StudentId = sch.StudentId
        WHERE
            sch.SubjectId = sub.SubjectId
        ORDER BY
            stu.Name
        FOR XML PATH('')
    ) x (Students)
;
3
Graeme

Que dis-tu de ça:

   ISNULL(SUBSTRING(REPLACE((select ',' FName as 'data()' from NameList for xml path('')), ' ,',', '), 2, 300), '') 'MyList'

Où le "300" pourrait être n'importe quelle largeur en tenant compte du nombre maximum d'éléments que vous pensez apparaître.

2
Hans Bluh

Une façon de procéder dans SQL Server consiste à renvoyer le contenu de la table au format XML (pour XML brut), à convertir le résultat en chaîne, puis à remplacer les balises par ",".

2
Manu
SELECT PageContent = Stuff(
    (   SELECT PageContent
        FROM dbo.InfoGuide
        WHERE CategoryId = @CategoryId
          AND SubCategoryId = @SubCategoryId
        for xml path(''), type
    ).value('.[1]','nvarchar(max)'),
    1, 1, '')
FROM dbo.InfoGuide info
2
Muhammad Bilal

Ci-dessous, une procédure PL/SQL simple pour implémenter le scénario donné en utilisant "boucle de base" et "rownum"

Définition de la table

CREATE TABLE "NAMES" ("NAME" VARCHAR2(10 BYTE))) ;

Insérons des valeurs dans ce tableau

INSERT INTO NAMES VALUES('PETER');
INSERT INTO NAMES VALUES('PAUL');
INSERT INTO NAMES VALUES('MARY');

La procédure commence à partir d'ici

DECLARE 

MAXNUM INTEGER;
CNTR INTEGER := 1;
C_NAME NAMES.NAME%TYPE;
NSTR VARCHAR2(50);

BEGIN

SELECT MAX(ROWNUM) INTO MAXNUM FROM NAMES;

LOOP

SELECT NAME INTO  C_NAME FROM 
(SELECT ROWNUM RW, NAME FROM NAMES ) P WHERE P.RW = CNTR;

NSTR := NSTR ||','||C_NAME;
CNTR := CNTR + 1;
EXIT WHEN CNTR > MAXNUM;

END LOOP;

dbms_output.put_line(SUBSTR(NSTR,2));

END;

Résultat

PETER,PAUL,MARY
2
Pooja Bhat

Bien qu'il soit trop tard, et a déjà de nombreuses solutions. Voici une solution simple pour MySQL:

SELECT t1.id,
        GROUP_CONCAT(t1.id) ids
 FROM table t1 JOIN table t2 ON (t1.id = t2.id)
 GROUP BY t1.id
2
Shahbaz

@ User1460901 Vous pouvez essayer quelque chose comme ceci:

WITH cte_base AS (
    SELECT CustomerCode, CustomerName,
    CASE WHEN Typez = 'Breakfast' THEN Items ELSE NULL END AS 'BREAKFAST'
    , CASE WHEN Typez = 'Lunch' THEN Items ELSE NULL END AS 'LUNCH'
    FROM #Customer
    )
    SELECT distinct CustomerCode, CustomerName,
    SUBSTRING(
    (   
        SELECT ','+BREAKFAST AS [text()]
        FROM cte_base b1
        WHERE b1.CustomerCode = b2.CustomerCode AND b1.CustomerName = b2.CustomerName
        ORDER BY b1.BREAKFAST
        FOR XML PATH('')
        ), 2, 1000
    ) [BREAKFAST], 
    SUBSTRING(
    (   
        SELECT ','+LUNCH AS [text()]
        FROM cte_base b1
        WHERE b1.CustomerCode = b2.CustomerCode AND b1.CustomerName = b2.CustomerName
        ORDER BY b1.LUNCH
        FOR XML PATH('')
        ), 2, 1000
    ) [LUNCH]
    FROM cte_base b2
1
Aura

Avec le type TABLE, c'est extrêmement facile. Imaginons que votre table s'appelle Students et qu'elle ait la colonne name.

declare @rowsCount INT
declare @i INT = 1
declare @names varchar(max) = ''

DECLARE @MyTable TABLE
(
  Id int identity,
  Name varchar(500)
)
insert into @MyTable select name from Students
set @rowsCount = (select COUNT(Id) from @MyTable)

while @i < @rowsCount
begin
 set @names = @names + ', ' + (select name from @MyTable where Id = @i)
 set @i = @i + 1
end
select @names

Cet exemple est testé dans MS SQL Server 2008 R2

1
Max Tkachenko

Avec une requête récursive, vous pouvez le faire:

-- Create example table
CREATE TABLE tmptable (NAME VARCHAR(30)) ;

-- Insert example data
INSERT INTO tmptable VALUES('PETER');
INSERT INTO tmptable VALUES('PAUL');
INSERT INTO tmptable VALUES('MARY');

-- Recurse query
with tblwithrank as (
select * , row_number() over(order by name) rang , count(*) over() NbRow
from tmptable
),
tmpRecursive as (
select *, cast(name as varchar(2000)) as AllName from tblwithrank  where rang=1
union all
select f0.*,  cast(f0.name + ',' + f1.AllName as varchar(2000)) as AllName 
from tblwithrank f0 inner join tmpRecursive f1 on f0.rang=f1.rang +1 
)
select AllName from tmpRecursive
where rang=NbRow
1
Esperento57

Il y a deux autres façons dans Oracle,

    create table name
    (first_name varchar2(30));

    insert into name values ('Peter');
    insert into name values ('Paul');
    insert into name values ('Mary');

    Solution 1:
    select substr(max(sys_connect_by_path (first_name, ',')),2) from (select rownum r, first_name from name ) n start with r=1 connect by prior r+1=r
    o/p=> Peter,Paul,Mary

    Soution 2:
    select  rtrim(xmlagg (xmlelement (e, first_name || ',')).extract ('//text()'), ',') first_name from name
    o/p=> Peter,Paul,Mary
1

Nous pouvons utiliser RECUSRSIVITY, WITH CTE, ALL ALL comme suit

declare @mytable as table(id int identity(1,1), str nvarchar(100))
insert into @mytable values('Peter'),('Paul'),('Mary')

declare @myresult as table(id int,str nvarchar(max),ind int, R# int)

;with cte as(select id,cast(str as nvarchar(100)) as str, cast(0 as int) ind from @mytable
union all
select t2.id,cast(t1.str+',' +t2.str as nvarchar(100)) ,t1.ind+1 from cte t1 inner join @mytable t2 on t2.id=t1.id+1)
insert into @myresult select *,row_number() over(order by ind) R# from cte

select top 1 str from @myresult order by R# desc
0
Kemal AL GAZZAH

sur la réponse de Chris Shaffer

si vos données peuvent être répétées telles que

Tom
ALi
John
ALi
Tom
Mike

Au lieu d'avoir Tom,ALi,John,ALi,Tom,Mike

Vous pouvez utiliser DISTINCT pour éviter les doublons et obtenir Tom,ALi,John,Mike

DECLARE @Names VARCHAR(8000) 
SELECT DISTINCT @Names = COALESCE(@Names + ',', '') + Name
FROM People
WHERE Name IS NOT NULL
SELECT @Names
0
asmgx