2016-08-24 1 views
1

T-SQLLa meilleure façon de concaténer 1 à n valeurs dans le champ unique à partir de deux tables

Imaginez deux tables qui ressemble à ceci:

Table: students 
============================== 
| TeacherID | SName   | 
| 1   | Thompson  | 
| 1   | Nickles  | 
| 2   | Cree   | 
============================== 

Table: teacher 
==================================================== 
| TeacherID | TName   | + many other fields | 
| 1   | Pipers  |      | 
| 2   | Slinger  |      | 
==================================================== 

Les noms de champs sont complètement arbitraires.

Je veux créer une requête avec la sortie suivante:

================================================================ 
| TeacherName | many other fields | Students     | 
| Pipers  |     | Thompson,Nickles   | 
================================================================ 

Actuellement, j'ai quelque chose comme ceci:

SELECT * 
FROM teacher 
LEFT JOIN (
    SELECT DISTINCT 
     EL2.teacherID, 
     STUFF((SELECT ',' + SName 
     FROM students 
     WHERE EL2.teacherID = students.teacherID 
     FOR XML PATH('') 
     ),1,1,'') AS "Students" 
    FROM students, teacher EL2) t1 
    ON t1.teacherID = teacher.teacherID 
WHERE t1.Students LIKE '%Thompson%' 

Cela fonctionne et me donne ce que je dois. La clause WHERE est d'illustrer que doit absolument être capable de filtrer si un enseignant a cet étudiant, mais ensuite mettre tous les élèves que l'enseignant a dans le champ concaténé.

Ma question est maintenant s'il y a une meilleure façon de le faire. je l'ai déjà regardé ceci: Concatenate many rows into a single text string?

Mais il ne m'a pas aidé beaucoup parce que je ne pouvais pas obtenir de travailler avec deux tables séparées et deux je ne pouvais pas filtrer la façon dont je avais besoin. Le plan d'exécution de SQL Management Studio indique que SELECT DISTINCT est très coûteux et d'autres ont indiqué que le recours à XML PATH n'est pas optimal car son comportement peut changer.

Répondre

1

Attention avec un DISTINCT sur les noms, comme vous pourriez avoir deux étudiants avec le même nom! Et BTW: GROUP BY est dans la plupart des cas, une meilleure approche performante pour obtenir une liste distincte ...

Vous pouvez essayer quelque chose comme ceci:

SELECT t.* 
     ,STUFF((SELECT ',' + s.SName 
     FROM students AS s 
     WHERE t.teacherID = s.teacherID 
     FOR XML PATH('') 
     ),1,1,'') AS Students 
FROM teacher AS t 
WHERE EXISTS(SELECT 1 FROM students AS x WHERE x.teacherID=t.teacherID /*AND [PUT YOUR FILTER HERE]*/) 

Si je comprends bien, vous voulez trouver seulement des enseignants où un étudiant donné est connecté à l'enseignant. Et dans ce cas, vous voulez trouver tous les étudiants liés à tous les enseignants connectés à l'étudiant donné, correct?

À la fin vous trouvez un /*AND [PUT YOUR FILTER HERE]*/ À cet endroit, vous devriez mettre quelque chose comme AND x.StudentId=123. Cela permettra de filtrer les enseignants pour les lignes liées à cet étudiant seulement. Pour ces enseignants, tous les élèves sont concaténés ...

+0

Ah comme je l'ai dit à TheGameiswar j'ai déjà essayé, mais je ne pouvais pas penser à un moyen de le filtrer car je n'avais plus accès aux champs (parce que SELECT étant proche de l'exécution). Avec le choix séparé à la fin cela fonctionne bien. Je vous remercie! – Splitframe

1

Utiliser le chemin XML, .. How for XML path works:

select 
TeacherID, 
Tname, 
stuff((select ','+s.sname from students s where s.teacherid=t.teacherid 
for xml path('')),1,1,'')as students 
from 
teachers t 
+0

J'avais cette approche auparavant, mais avec cela, je n'ai pas pu filtrer les noms des élèves et obtenir toujours tous les élèves associés dans le champ concaténé. – Splitframe

+0

gagné; t ce travail pour vos données d'échantillon – TheGameiswar