2010-05-29 67 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' 

將它加入學生表應該不難。