Student
| student_id | name |
|---|---|
| 1 | 철수 |
| 2 | 영희 |
| 3 | 민수 |
Course
| course_id | title |
|---|---|
| 101 | 수학 |
| 102 | 영어 |
| 103 | 과학 |
| 104 | 미술 |
CourseEnroll
| student_id | course_id |
|---|---|
| 1 | 101 |
| 1 | 102 |
| 2 | 103 |
[INNER] JOIN ... ON ...-- 학생이 수강한 과목 중 특정 과목(예: course_id=101, 수학)을 제외한 나머지 과목을 조회하기
SELECT S.name, C.title
FROM CourseEnroll CE
INNER JOIN Student S ON CE.student_id=S.student_id
INNER JOIN Course C ON CE.course_id=C.course_id
WHERE CE.course_id<>101;

[INNER] JOIN ... ON ...-- 학생이 수강한 과목 조회하기
SELECT S.name, C.title
FROM CourseEnroll CE
INNER JOIN Student S ON CE.student_id=S.student_id
INNER JOIN Course C ON CE.course_id=C.course_id;

NATURAL JOIN ...-- 학생이 수강한 과목 조회하기
SELECT S.name, C.title
FROM CourseEnroll CE
Natural JOIN Student S
Natural JOIN Course C;

LEFT OUTER JOIN
LEFT [OUTER] JOIN … ON …-- 모든 학생의 과목 수강 상태 표시. 수강 과목이 없으면 NULL
SELECT S.name, C.title
FROM student S
LEFT OUTER JOIN courseenroll CE ON S.student_id = CE.student_id
LEFT OUTER JOIN course C ON CE.course_id = C.course_id;

✔️ 다중 조인의 구체적인 동작방식
-- 첫 번째 조인: student[왼] + courseenroll[오] FROM student S LEFT OUTER JOIN courseenroll CE ON S.student_id = CE.student_id
S.student_id S.name CE.student_id CE.course_id 1 철수 1 101 1 철수 1 102 2 영희 2 103 3 민수 NULL NULL -- 두 번째 조인: (student + courseenroll)[왼] + course[오] LEFT OUTER JOIN course C ON CE.course_id = C.course_id
S.student_id S.name CE.student_id CE.course_id C.course_id C.title 1 철수 1 101 101 수학 1 철수 1 102 102 영어 2 영희 2 103 103 과학 3 민수 NULL NULL NULL NULL
RIGHT OUTER JOIN
RIGHT [OUTER] JOIN … ON …-- 모든 과목을 기준으로 수강상태 표시. 수강생이 없으면 NULL
SELECT C.title, S.name
FROM Student S
RIGHT OUTER JOIN CourseEnroll CE ON CE.student_id=S.student_id
RIGHT OUTER JOIN Course C ON C.course_id=CE.course_id;

✔️ 다중 조인의 구체적인 동작방식
-- 첫 번째 조인: Student[왼] + CourseEnroll[오] FROM Student S RIGHT OUTER JOIN CourseEnroll CE ON CE.student_id=S.student_id
S.student_id S.name CE.student_id CE.course_id 1 철수 1 101 1 철수 1 102 2 영희 2 103 -- 두 번째 조인: (CourseEnroll + Student)[왼] + Course[오] RIGHT OUTER JOIN Course C ON C.course_id=CE.course_id;
S.student_id S.name CE.student_id CE.course_id C.course_id C.title 1 철수 1 101 101 수학 1 철수 1 102 102 영어 2 영희 2 103 103 과학 NULL NULL NULL NULL 104 미술
FULL OUTER JOIN
UNION-- LEFT JOIN: 학생 기준으로 모든 행 포함
SELECT s.name AS student_name, c.title AS course_title
FROM student s
LEFT JOIN courseenroll ce ON s.student_id = ce.student_id
LEFT JOIN course c ON ce.course_id = c.course_id
UNION
-- RIGHT JOIN: 과목 기준으로 모든 행 포함
SELECT s.name AS student_name, c.title AS course_title
FROM student s
RIGHT JOIN courseenroll ce ON s.student_id = ce.student_id
RIGHT JOIN course c ON ce.course_id = c.course_id;

EXISTS 혹은 IN을 사용-- EXISTS 사용 예
-- 수강과목이 있는 학생들만 표시. 과목정보는 표시 X
SELECT s.name
FROM student s
WHERE EXISTS (
SELECT 1
FROM courseenroll ce
WHERE ce.student_id = s.student_id
);
✔️
SELECT 1을 사용하는 이유
- EXISTS는 조건에 맞는 데이터가 존재하는지 존재 여부만 궁금할 뿐 정확히 어떤 데이터가 있는지는 관심이 없다.
- 무겁게 데이터를 반환하지 않고 가벼운 1만을 받아서 존재여부를 판단
- 1을 반환하면 존재한다는 의미 / 아무것도 반환하지 않는다면 존재하지 않는다는 의미.
-- IN 사용 예
-- 만약 s.student_id에 NULL 이 있으면 결과는 달라지므로 처리해야 함. EXISTS 권장
SELECT s.name
FROM student s
WHERE s.student_id IN (
SELECT ce.student_id
FROM courseenroll ce
);
✔️ IN 동작방식
- 서브쿼리 실행하여 명단 만들기
- 메인 쿼리 대조하기
: student 테이블에서 student_id를 하나씩 꺼내와 서브쿼리 명단과 일일이 대조
✔️ 주의해야 할 점 - NULL
SQL에서 NULL은 비어있는 값이 아니라 ‘아직 모르는 값(Unknown)’이라는 의미를 가진다.
- 예1) NULL
IN(1, 1, 2)
- NULL이 1, 2일 수도 있는 가능성 존재 → UNKNOWN → FALSE 처리
- 예2) 3
NOT IN(1, 2, NULL)
- NULL이 3일 수도 있는 가능성 존재 → UNKNOWN → 아무것도 출력X
⇒ EXISTS 사용 권장!
EXISTS / IN 실행 결과
= 조건으로 매칭 (가장 흔함)EXISTS, IN)