2010-05-29 73 views
0

问一个简单的问题,只是希望每个人都有乐趣去解决它。 我有2张桌子。 1.学生 2.课程sql select with exact results

学生

+----+--------+ 
| id | name | 
+----+--------+ 
| 1 | User1 | 
| 2 | User2 | 
+----+--------+ 

+----+------------+------------+ 
| id | student_id | course_name| 
+----+------------+------------+ 
| 1 |   1 | English | 
| 2 |   1 | Chinese | 
| 3 |   2 | English | 
| 4 |   2 | Japanese | 
+----+------------+------------+ 

我希望得到的结果所有的学生,谁采取英语和中国,不是英语或中国。

预期的结果:

+----+------------+------------+ 
    | id | student_id | course_name| 
    +----+------------+------------+ 
    | 1 |   1 | English | 
    | 2 |   1 | Chinese | 
    +----+------------+------------+ 

我们通常做的是

select * from student join course on (student.id = course.student_id) WHERE course_name = 'English' OR course_name = 'Chinese' 

,但这样的结果,我可以得到这不是我期望的结果用户2记录。我只想记录只显示用户参加英语+中文课程。

+0

如果这是作业,请认真标记它。为了清楚起见,添加一个不符合标准的学生。 – 2010-05-29 12:47:04

+0

已经有一个学生不符合标准 - 一个与student_id = 2 ... – ivans 2010-05-29 12:49:35

+0

这不是一个家庭作业,我不是学生了,我实际上解决更复杂的搜索标准,这只是简化版本的一个例子。大多数网站都有多个搜索条件,我确定他们使用OR来获得结果。我在想什么,如果人们想要完全的2门课程,不用或者。我知道通过使用或也会得到预期的结果之一,但也得到不必要的。这就是为什么我出现这个想法。 – Shiro 2010-05-29 13:05:40

回答

3

只要加入到课程两次:一次为英文,一次为中文。那就是:

select student.* 
from student 
    join course english_course on student.id = english_course.student_id 
    join course chinese_course on student.id = chinese_course.student_id 
where english_course.course_name = 'English' 
     and chinese_course.course_name = 'Chinese' 

甚至

select * from student 
where exists (select 1 from course 
       where course.course_name = 'English' and course.student_id = student.id) 
     and exists (select 1 from course 
        where course.course_name = 'Chinese' and course.student_id = student.id); 

这也将消除重复的课程(student_id数据,课程名称)的条目。

我假设(student_id,course_name)被索引来驱动这两个。您的命名有点奇怪:“课程”表格没有描述课程,它描述了从学生到课程的关联。就我个人而言,我称它为“student_course”(或类似的,可能是后缀“_map”或“_link”),并让它包含引用具有ID和名称的课程表的“course_id”。

(我也希望有统一进行命名的主键,而不是在他们自己的表称他们为“ID”,不过这只是被挑剔,并更加主观的)

只是为了好玩:

select student.* 
from student 
    join course on student.id = course.student_id 
where course.course_name = 'English' 
intersect 
select student.* 
from student 
    join course on student.id = course.student_id 
where course.course_name = 'Chinese' 

现实情况是,使用“相交”来比较基于相同表的两个结果集有点愚蠢。

+0

对于奇怪的命名抱歉,我只是写它为示例目的。在真实数据中,我使用ID作为参考。 – Shiro 2010-05-29 13:06:54

1

您可以使用having子句来执行,以匹配:

select s.student_id 
from student s 
join course c 
on  s.id = c.student_id 
     and c.course_name in ('English', 'Chinese') 
group by 
     s.student_id 
having count(distinct c.course_name) = 2 

要检索等栏目,你可以加入此查询:

select * 
from student s 
join course c 
on  s.id = c.student_id 
join (
     <query from above here> 
     ) filter on s.id = filter.student_id 
+0

如果学生选了两门课,会发生什么?你理论上可以从英文两次的人那里得到结果,而且不会拿中文。 – ivans 2010-05-29 12:44:16

+0

@ivans:'count'中的'distinct'(独特...'确保它匹配中文和英文 – Andomar 2010-05-29 12:51:09

+0

哎呀,对不起。当我第一次阅读时没有看到它:-( – ivans 2010-05-29 12:51:55

0

您可以使用IN操作符

select * from student join course on (student.id = course.student_id) 
WHERE course_name = 'English' and student.id IN 
(select student.id from student join course on (student.id = course.student_id) 
WHERE course_name = 'Chinese') 
0

您可能想要自行加入:

SELECT left.student_id sid1, right.student_id sid2, 
     left.course_name cn1, right.course_name cn2 
FROM course left, course right 
WHERE sid1 = sid2 AND 
     cn1 = 'English' AND cn2 = 'Chinese' 

将它加入学生表应该不难。