将两个表中的 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
这样的东西。这会将教师过滤到仅与该学生相关的行。对于这些老师,所有学生都串联...
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
这样的东西。这会将教师过滤到仅与该学生相关的行。对于这些老师,所有学生都串联...