简体   繁体   中英

An SQL query to get the exact matching results

In my MySQL database, I have three tables students , classes , courses .

One class has many students .

One class has many courses .

The courses table has one boolean field active , and a string field name .

So overall relationship is (sorry I am not sure how to better illustrate the relationship if it is not clear):

students (many_to_one) classes (one_to_many) courses

I have a function in Ruby that accepts an array of strings argument for the course name s:

def get_student_names_whose_courses_are(active_course_names)
   # Run a raw SQL query for the result
end

I would like to write a raw SQL query to get the names of students whose courses (via class ) matches exactly the passed in argument course names and are active.

For example, if active_course_names holds values ['foo','bar'] . Student-A has active courses 'foo','bar','etc', student-B has active courses 'foo' and 'bar'. The raw quesry should only return student-B, even though student-A also has the two courses active, the point is an exact matching.

What I tried is this:

select stu.name
from students stu
inner join classes clz ON clz.id = stu.class_id
inner join courses cour ON cour.class_id = clz.id AND cour.name in (#{active_course_names,join("','")})
where cour.active = true;

But with this, it returns both student-A and student-B for the example above. How to make the query so that it returns students that have exactly the active courses?

My demo exapmle here

I hope the following answer would be of help to your problem.

If you assign a rank in the same courses (for instance 'FOO'), then you can keep the courses which are repeated in the classes (rank>1) and apply your list of courses. After creating that, you can perform the join to bring the students' information that you need.

SELECT Temp.name,stud.id,stud.name,stud.class_id
FROM (
  /*Create a view with the courses which are present with another classroom*/
  SELECT T.id, T.name, T.active,T.class_id
  FROM (
    /*Create a view with only the active courses and their rank*/
    SELECT id,name,active,class_id,
      @course_rank := IF(@current_course = name,
      @course_rank + 1, 1) AS course_rank,
      @current_course := name
    FROM courses,(select @current_course :=0,@course_rank :=0)  r
    WHERE active = 1
    ORDER BY name, class_id ASC)T
  /*Create a filter to bring only the classrooms with the same courses and the selected courses*/
  WHERE T.course_rank>1 AND T.name IN ('foo','bar'))Temp
JOIN students stud
ON Temp.class_id=stud.class_id

Try this:

select distinct student from (
select stu.name student, cour.name course, count(cour.name )
from students stu
inner join classes clz ON clz.id = stu.class_id
inner join courses cour ON cour.class_id = clz.id 
where cour.active = true
and cour.name in ('foo','bar')
group by stu.name , cour.name
having count(course) =2) A;

Here is the DEMO

In this DEMO only stu-A needs to be selected. Number 2 marks that student only has this two courses active and not 3 of them. Hope this is it...

This is a relational division problem with added "no remainder" condition. One of the simpler solution is this:

SELECT students.name, students.id
FROM students
JOIN classes ON students.class_id = classes.id
JOIN courses ON classes.id = courses.class_id
WHERE courses.active = true
GROUP BY students.name, students.id
-- if student is enrolled in both courses and no other then:
-- count(*) would be 2
-- count(course in foo, bar) would also be 2
HAVING COUNT(*) = 2
   AND COUNT(CASE WHEN courses.name IN ('foo', 'bar') THEN 1 END) = 2

You can use group_concat like this:

SELECT 
     stu.name, 
     GROUP_CONCAT(cour.name ORDER BY cour.name ASC) AS courses
FROM students stu
inner join classes clz ON clz.id = stu.class_id
inner join courses cour ON cour.class_id = clz.id
where 
     cour.active = true
GROUP BY stu.name
HAVING GROUP_CONCAT(cour.name ORDER BY cour.name ASC) = 'bar,foo'

DEMO IS HERE

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM