80 votes

Combinez plusieurs résultats dans une sous-requête en une seule valeur séparée par des virgules.

J'ai deux tables :

TableA
------
ID, Name

TableB
------
ID, SomeColumn, TableA_ID (FK for TableA)

La relation est une ligne de TableA - de nombreux TableB .

Maintenant, je veux voir un résultat comme celui-ci :

ID     Name      SomeColumn

1.     ABC       X, Y, Z (these are three different rows)
2.     MNO       R, S

Cela ne fonctionnera pas (plusieurs résultats dans une sous-requête) :

SELECT ID, Name, (SELECT SomeColumn FROM TableB WHERE F_ID=TableA.ID) FROM TableA

C'est un problème trivial si je fais le traitement du côté client. Mais cela signifie que je devrai exécuter X requêtes sur chaque page, où X est le nombre de résultats de TableA .

Notez que je ne peux pas simplement faire un GROUP BY ou quelque chose de similaire, car cela renverrait des résultats multiples pour les rangées de TableA .

Je ne suis pas sûr qu'un UDF, utilisant COALESCE ou quelque chose de similaire, puisse fonctionner ?

131voto

priyanka.sarkar Points 5980

Même ceci servira le but

Exemple de données

declare @t table(id int, name varchar(20),somecolumn varchar(10))
insert into @t
    select 1,'ABC','X' union all
    select 1,'ABC','Y' union all
    select 1,'ABC','Z' union all
    select 2,'MNO','R' union all
    select 2,'MNO','S'

Une requête :

select ID,Name,
    stuff((select ',' + CAST(t2.SomeColumn as varchar(10))
     from @t t2 where t1.id = t2.id and t1.name = t2.name
     for xml path('')),1,1,'') SomeColumn
from @t t1
group by id,Name

Sortie :

ID  Name    SomeColumn
1   ABC     X,Y,Z
2   MNO     R,S

45voto

Donniel Thomas Points 1048

1. Créez l'UDF :

CREATE FUNCTION CombineValues
(
    @FK_ID INT -- The foreign key from TableA which is used 
               -- to fetch corresponding records
)
RETURNS VARCHAR(8000)
AS
BEGIN
DECLARE @SomeColumnList VARCHAR(8000);

SELECT @SomeColumnList =
    COALESCE(@SomeColumnList + ', ', '') + CAST(SomeColumn AS varchar(20)) 
FROM TableB C
WHERE C.FK_ID = @FK_ID;

RETURN 
(
    SELECT @SomeColumnList
)
END

2. Utilisation dans une sous-requête :

SELECT ID, Name, dbo.CombineValues(FK_ID) FROM TableA

11voto

Ben Hoffstein Points 44398

Je pense que vous êtes sur la bonne voie avec COALESCE. Voir ici pour un exemple de construction d'une chaîne délimitée par des virgules :

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

10voto

Jacob Points 2141

Dans MySQL, il existe un groupe_concat qui renverra ce que vous demandez.

SELECT TableA.ID, TableA.Name, group_concat(TableB.SomeColumn) 
as SomColumnGroup FROM TableA LEFT JOIN TableB ON 
TableB.TableA_ID = TableA.ID

0voto

Bill Points 1532

Vous devrez peut-être fournir quelques détails supplémentaires pour obtenir une réponse plus précise.

Comme votre ensemble de données semble assez étroit, vous pourriez envisager d'utiliser une ligne par résultat et d'effectuer le post-traitement au niveau du client.

Si vous voulez vraiment que le serveur fasse le travail, renvoyez un jeu de résultats comme suit

ID       Name       SomeColumn
1        ABC        X
1        ABC        Y
1        ABC        Z
2        MNO        R
2        MNO        S

qui est bien sûr un simple INNER JOIN sur ID

Une fois que vous avez récupéré le jeu de résultats sur le client, maintenez une variable appelée CurrentName et utilisez-la comme déclencheur pour arrêter la collecte de SomeColumn dans la chose utile que vous voulez qu'elle fasse.

Prograide.com

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.

Powered by:

X