将两个表中的 1 到 n 值连接到单个字段的最佳方法

Best way to concat 1 to n values into single field from two tables

T-SQL

假设两个表如下所示:

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

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

字段名称完全是任意的。

我想创建一个具有以下输出的查询:

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

目前我有这样的东西:

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%'

这行得通,满足了我的需要。 WHERE 子句是为了说明我 还绝对需要能够过滤教师是否有该学生,然后将教师拥有的所有学生都放入连接字段中。

我现在的问题是是否有更好的方法来做到这一点。 我已经看过这个: Concatenate many rows into a single text string?

但它对我没有太大帮助,因为一个我无法让它与两个单独的表一起工作,两个我无法按照我需要的方式进行过滤。

SQL Management Studio 执行计划表明 SELECT DISTINCT 是 非常昂贵,其他人说对 XML PATH 的依赖不是最佳的,因为它的行为可以改变。

使用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

小心名字上的 DISTINCT,因为您可能有两个同名的学生!顺便说一句:GROUP BY 在大多数情况下是一种获得不同列表的更好的方法...

您可以尝试这样的操作:

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]*/)

如果我没有理解错的话,您只想查找某个给定学生与教师有关联的教师。在这种情况下,您想要找到绑定到与给定学生相关的所有教师的所有学生,对吗?

最后你会发现一个 /*AND [PUT YOUR FILTER HERE]*/ 在这个地方你应该放一些像 AND x.StudentId=123 这样的东西。这会将教师过滤到仅与该学生相关的行。对于这些老师,所有学生都串联...