mysql SQL:获得一级、二级和三级关联的优雅方法

ix0qys7i  于 2023-01-20  发布在  Mysql
关注(0)|答案(3)|浏览(286)

我在MySQL数据库中有几个名为coursestudentstudents_in的表。

    • 课程**
course_id       name
    3             Physics
   12             English
   19             Basket Weaving
    4             Computer Science
  212             Discrete Math
  102             Biology
   20             Chemistry
   50             Robotics
    7             Data Engineering
    • 学生**
id    name
 2    Sally
 1    Bob
17    Robert
 9    Pierre
12    Sydney
41    James
22    William
 5    Mary
 3    Robert
92    Doris
 6    Harry
    • 学生_在**
course_id   student_id      grade
    3              2              B
  212              2              A
    3             12              A
   19             12              C
    3             41              A
    4             41              B
  212             41              F
   19             41              A
   12             41              B
    3             17              C
    4              1              A
  102              1              D
  102             22              A
   20             22              A
   20              5              B
   50              3              A
   12             92              B
   12             17              C
    7              6              A

这里有一个小提琴:http://sqlfiddle.com/#!17/8d86ee/34
我的目标是让以下学生获得idname
1.与Sally一起参加过课程(即"一级"关系),
1.与Sally一起上过课的人一起上过课(即"二级"关系),
1.与曾与Sally一起上过课的人一起上过课(即"第三关系"关系)
基本上,我们要找的是与莎莉的一级、二级和三级关系。
下面是对这一过程的描述:

由于Sally选修了课程ID 3和212,所需的结果将如下所示(不是上面的彩色表格,我提供该表格是为了说明所涉及的逻辑):

student_id       student_name
    12           Sydney             <-- took course ID 3 with Sally
    41           James              <-- took course ID 3 and 212 with Sally
    17           Robert             <-- took course ID 3 with Sally
     1           Bob                <-- took course ID 4 with James
    92           Doris              <-- took course ID 12 with James and Robert
   102           William            <-- took course ID 102 with Bob

我试图通过使用公共表表达式(CTE)查询一级关系来解决这个问题,并且可能可以使用两个额外的CTE来获得二级和三级关系,但是,这感觉像是一种非常不优雅的方法。
有人能用一种优雅的方法来解决这个问题吗?
谢谢大家!

h9vpoimq

h9vpoimq1#

您可以使用递归cte

with recursive cte(cid, sid, name, l) as (
   select si.course_id, si.student_id, s.name, 1 from students_in si 
   join student s on s.id = si.student_id where si.course_id in (select si1.course_id 
      from students_in si1 join student s1 on s1.id = si1.student_id and s1.name = 'Sally') and s.name != 'Sally'
   union all
   select si.course_id, si.student_id, s.name, c.l + 1 from cte c 
   cross join students_in si
   join student s on s.id = si.student_id 
   where si.course_id in (select si1.course_id 
      from students_in si1 where si1.student_id = c.sid) and si.course_id  != c.cid and si.student_id != c.sid and c.l < 3
)
select distinct sid, name from cte where name != 'Sally'

See fiddle.

6l7fqoea

6l7fqoea2#

With Recursive coursemates As (
    Select y.student_id, 1 as removal
    From students_in x Inner Join students_in y
        On x.course_id=y.course_id
    Where x.student_id=2
  UNION
    Select y.student_id, r.removal+1
    From coursemates r Inner Join students_in x
        On r.student_id=x.student_id
      Inner Join students_in y
        On x.course_id=y.course_id
    Where removal<=2
)
Select c.student_id, min(c.removal) as howfar, min(s.name) as student_name
From coursemates c Left Outer Join student s
    On c.student_id=s.student_id
Where student_id <> 2
Group By c.student_id
Order by 2, 1

有点冗长,但也比您的尝试更一般化,因为您可以控制深度。
一些防御性补充:1.在学生表上进行左连接,以防那里没有R.I.。2.从结果中过滤掉Sally(不关心Robert和Sally在一起,然后Sally和Robert在一起)

laawzig2

laawzig23#

根据需要多次重复加入,也不错,但可能不太优雅:)

with rel as ( --join student->student thru course
select t1.student_id s1Id, t2.student_id s2Id 
from students_in t1 inner join students_in t2 
  on t2.course_id=t1.course_id
where t2.student_id<>t1.student_id
group by t1.student_id,t2.student_id
)
,four as(
select  t1.s1Id as s1Id1 ,t2.s1Id s2Id1,t2.s2Id s2Id2 ,t3.s2Id s3Id2 
from rel t1 left join rel t2 on t2.s1Id=t1.s2Id and t2.s2Id<>t1.s1Id
 left join rel t3  on t3.s1Id=t2.s2Id and t2.s2Id<>t1.s1Id
      and t3.s2Id<>t1.s1Id
where  t1.s1Id=2  
group by t1.s1Id ,t2.s1Id,t2.s2Id,t3.s2Id
)
select t1.s1Id1,t1,s3Id2,s1.name,s3.name,s4.name,s6.name
from four t1
inner join student s1 on t1.s1Id1=s1.id
inner join student s3 on t1.s2Id1=s3.id
inner join student s4 on t1.s2Id2=s4.id
inner join student s6 on t1.s3Id2=s6.id

相关问题