2010-05-29 5 views
0

간단한 질문을 던지십시오. 2 개의 테이블이 있습니다. 1. 학생 2. 코스정확한 결과를 가진 SQL을 선택하십시오

학생

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

코스

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

나는 결과를 영어와 중국어, NOT 영어 또는 중국어 촬영 한 모든 학생을 좀하고 싶습니다.

예상 결과 :

+----+------------+------------+ 
    | 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

숙제 인 경우이를 그대로 기재하십시오. 그리고 명확성을 위해 기준을 충족시키지 못하는 학생을 추가하십시오. –

+0

기준을 충족시키지 못하는 학생은 이미 있습니다. student_id = 2 ... – ivans

+0

이것은 숙제가 아니며 학생이 아니며 더 복잡한 검색 기준을 실제로 풀었습니다. 단순화 된 버전의 예제. 대부분의 웹 사이트는 여러 검색 기준을 사용합니다. 결과를 얻기 위해 OR을 사용하고있는 것은 틀림 없습니다. 내가 생각하고있는 것, 사람들이 정확하게 2 코스를 원한다면, 또는 사용하지 않는다면 어떨까요? 또한 OR을 사용하여 예상 결과 중 하나를 얻을 수도 있지만 원치 않는 결과를 얻을 수도 있습니다. 이것이 내가이 마음에서 나오는 이유입니다. – Shiro

답변

3

코스에 두 번 가입하십시오. 한 번 영어로, 한 번 중국어로. 즉 : 물론 중복 (student_id, COURSE_NAME) 항목을 제거합니다

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, 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' 

"intersect"를 사용하면 동일한 테이블을 기반으로 두 결과 세트를 비교하는 것이 약간 바보입니다.

+0

이상한 명명을 위해 미안 해요, 그냥 샘플 데이터입니다. 실제 데이터에서 ID를 참조로 사용하고 있습니다. – Shiro

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

+0

@ivans :'count (distinct ...) '의'distinct '는 중국어와 영어 모두 일치하는 것을 보장합니다. – Andomar

+0

죄송합니다. 처음 읽는 동안 보지 못했습니다 :-( – ivans

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' 

학생 테이블에 합치는 것이 어렵지 않아야합니다.

관련 문제