返回每个类别至少有一个的{student_ids}

时间:2019-02-14 23:11:21

标签: sql oracle

说,我们有三个表格,分别是学生,作业和科目。我要返回该学生在名为first_name ='place'和last_name ='holder'的学生完成的每个科目中至少完成一项作业的所有学生ID。

学生桌:

Student_id | first_name | last_name
------------------------------------
     1     |   place    | holder
     2     |            |           
     3     |            |

主题:

subject_id | name
-----------------
     1     | Math
     2     | English
     3     | Science

任务:

student_id | subject_id
-----------------------
     1     |    1
     1     |    2
     1     |    3
     2     |    1
     2     |    2
     2     |    3
     3     |    1
     3     |    2

因此,在这种情况下,我希望查询结果为:

student_id
----------
     1
     2

我尝试了许多不同的方法,例如使用set操作和类似的方法,但是似乎没有一个方法能获得正确的结果。我不断吸引所有在“占位符”学生中完成任务的任何科目中至少完成一项任务的学生。

3 个答案:

答案 0 :(得分:0)

您可以使用SQL Join获得所需的结果。假设每个科目只有一个作业:

SELECT students.student_id FROM students
INNER JOIN assignments on assignments.student_id = students.student_id
GROUP BY students.student_id
HAVING COUNT(*) = (SELECT COUNT(*) FROM subjects)

答案 1 :(得分:0)

联接两个表SubjectsAssignments就足够了。您需要达到所需学生的学科数量。

with Subjects( subject_id, name) as
(
 select 1,'Math'    from dual union all
 select 2,'English' from dual union all
 select 3,'Science' from dual
),   
     Assignments( student_id, subject_id) as
(     
 select 1,1 from dual union all
 select 1,2 from dual union all 
 select 1,3 from dual union all
 select 2,1 from dual union all
 select 2,2 from dual union all
 select 2,3 from dual union all
 select 3,1 from dual union all
 select 3,2 from dual
)
select student_id
  from ( select count(distinct subject_id) as subject_id from Subjects ) s
  join Assignments a on a.subject_id = s.subject_id 

student_id
----------
1
2 

答案 2 :(得分:0)

在其他答案中,我没有看到占位符名称作为查询条件,我认为这是要求的一部分。我将其分解为带有注释的初步查询,以便您了解最终解决方案的构建方式:

--this will get a 'standard' list of subjects 
--(with at least one completed assignment by the 'standard' student)
--to which all students will be compared
select distinct subject_id
from assignments a
inner join students s
on s.student_id = a.student_id
where s.first_name = 'place'
and s.last_name = 'holder';


--cross join the students and the list above 
--we will outer join this to the assigments table later
select students.student_id as std_student, standard_subjects.subject_id as std_subj
from students, 
(select distinct subject_id
from assignments a
inner join students s
on s.student_id = a.student_id
where s.first_name = 'place'
and s.last_name = 'holder') standard_subjects;


--outer join this to a set of completions 
--to compare actual completions to 
--the standard set by the 'placeholder' student
with completions as (select student_id, subject_id 
from assignments
group by student_id, subject_id
) 
select std_student, std_subj, student_id
from (select students.student_id as std_student, standard_subjects.subject_id as std_subj
from students, 
(select distinct subject_id
from assignments a
inner join students s
on s.student_id = a.student_id
where s.first_name = 'place'
and s.last_name = 'holder') standard_subjects) standard
left join completions
on standard.std_student = completions.student_id
and standard.std_subj = completions.subject_id;


--sum up the completions and select only the students
--having a completion in each 'standard' subject
select std_student as result 
from (
with completions as (select student_id, subject_id 
from assignments
group by student_id, subject_id
) 
select std_student, std_subj, student_id
from (select students.student_id as std_student, standard_subjects.subject_id as std_subj
from students, 
(select distinct subject_id
from assignments a
inner join students s
on s.student_id = a.student_id
where s.first_name = 'place'
and s.last_name = 'holder') standard_subjects) standard
left join completions
on standard.std_student = completions.student_id
and standard.std_subj = completions.subject_id) comparison
having count(student_id) = count(std_subj)
group by std_student;