CodeGym /행동 /SQL SELF /JOIN에서 추가 조건: ON ... AND ...

JOIN에서 추가 조건: ON ... AND ...

SQL SELF
레벨 12 , 레슨 2
사용 가능

이미 JOIN으로 테이블을 합치는 방법은 알고 있지? 근데 실제로는 키 값만 맞춘다고 끝나는 게 아니야. 종종 추가 조건이 맞는 데이터만 합쳐야 할 때가 많아 — 예를 들어, 활성화된 데이터만, 올해 데이터만, 완료된 주문만 등등.

이럴 때 ONAND를 붙여서 조건을 확장하는 게 진짜 유용해.

JOIN ... ON에서 추가 조건을 쓰면 어떤 행이 조인에 들어갈지 정확하게 컨트롤할 수 있어. SQL이 결과를 만들기 전에 미리 걸러주니까, 쿼리가:

  • 더 빨라져 (JOIN을 통과하는 행이 적으니까),
  • 더 정확해져 (조인 단계에서 필터링하니까),
  • 특히 LEFT JOIN에서 예측 가능해져 (WHERE에서 필터링하는 것과 다르게).

예시: 활성화된 수강신청만

예를 들어, enrollments 테이블에는 학생의 참여 상태가 있어: active, dropped, pending.

students 테이블:

id name
1 Otto Song
2 Maria Chi
3 Alex Lin

enrollments 테이블 업데이트:

student_id course_id status
1 101 active
1 103 active
2 102 dropped
3 101 active

courses 테이블:

id name
101 Mathematics
102 Physics
103 Computer Science

이제 활성화된 수강신청이 있는 학생만 뽑고 싶어:

SELECT 
    students.name AS student_name,
    courses.name AS course_name
FROM students 
INNER JOIN enrollments 
    ON students.id = enrollments.student_id
    AND enrollments.status = 'active'
INNER JOIN courses 
    ON enrollments.course_id = courses.id;

결과:

student_name course_name
Otto Song Mathematics
Otto Song Computer Science
Alex Lin Mathematics

여기서 AND enrollments.status = 'active'ON 안에 넣어서 활성화된 데이터만 조인되게 한 거야. 조인 후에 필터링하는 게 아니고!

WHERE가 아니야?

이렇게도 쓸 수 있지:

...
WHERE enrollments.status = 'active'

근데 이건 LEFT JOIN에서 동작이 달라. WHERE에서 필터링하면 매칭 안 되는 행(NULL)이 다 날아가서 LEFT JOININNER JOIN처럼 돼버려.

반면에 ON 안에 AND enrollments.status = 'active'를 넣으면, 조인에 들어갈 행 자체를 제한하는 거라서 결과만 필터링하는 게 아니야.

이런 방식은 한쪽 테이블에 매칭되는 값이 없어도 행을 남기고 싶을 때(리포트나 분석에서 자주 쓰임) 특히 중요해.

다른 ON ... AND ... 활용 예시

students 테이블:

id name
1 Otto Song
2 Maria Chi
3 Alex Lin

enrollments 테이블:

student_id course_id status enrolled_at
1 101 active 2025-02-01
1 103 active 2025-03-05
2 102 dropped 2024-05-15
3 101 active 2025-03-12

courses 테이블:

id name
101 Math
102 Physics
103 CS

예시: 올해 수강신청만

SELECT
    students.name,
    courses.name,
    enrollments.enrolled_at
FROM students
JOIN enrollments
    ON students.id = enrollments.student_id
    AND EXTRACT(YEAR FROM enrollments.enrolled_at) = EXTRACT(YEAR FROM CURRENT_DATE)
JOIN courses
    ON enrollments.course_id = courses.id;

여기서는 올해에 해당하는 데이터만 조인했어.

name name enrolled_at
Otto Song Math 2025-02-01
Otto Song CS 2025-03-05
Alex Lin Math 2025-03-12

예시: 특정 값 제외하기

JOIN enrollments
    ON students.id = enrollments.student_id
    AND enrollments.status != 'dropped'

수강 취소한 학생은 조인 단계에서 빼버려. 나중에 필터링하는 게 아니고!

name name
Otto Song Math
Otto Song CS
Alex Lin Math

ON 안에 조건을 넣으면 PostgreSQL이 조인 플랜을 더 최적화해서 처리할 행이 줄어들어. 데이터가 많을수록 이게 진짜 중요해. 조인 후에 거르는 것보다 내부 필터링이 훨씬 효율적이야.

JOIN ON키만 쓰는 게 아니야

많은 사람들이 ON에는 그냥 id = id만 넣는다고 생각하는데, 사실 여기에 이런 것도 넣을 수 있어:

  • 논리 연산자: AND, OR, NOT
  • 비교: >, <, <>, BETWEEN, IN
  • 표현식: EXTRACT, DATE_TRUNC, COALESCE, NULLIF

다 같이 조합해보자

students 테이블:

id name
1 Otto Song
2 Maria Chi
3 Alex Lin

faculties 테이블:

id name
10 Engineering
20 Natural Sciences
30 ← 이름 없음 (NULL)

courses 테이블:

id name teacher faculty_id
101 Math Liam Park 10
102 Physics Chloe Zhang 20
103 CS Noah Kim 10
104 PE Ava Chen 30

enrollments 테이블:

student_id course_id status
1 101 active
1 103 active
2 102 dropped
3 101 active
3 104 active
SELECT
    s.name AS student_name,
    c.name AS course_name,
    f.name AS faculty_name
FROM students s
JOIN enrollments e
    ON s.id = e.student_id
    AND e.status = 'active'
JOIN courses c
    ON e.course_id = c.id
    AND c.name != 'PE'
JOIN faculties f
    ON c.faculty_id = f.id
    AND f.name IS NOT NULL;

여기서 동시에 필터링하는 조건은:

  • 활성화된 데이터,
  • "PE" 과목 제외,
  • 이름이 있는 학부만.

쿼리 결과:

student_name course_name faculty_name
Otto Song Math Engineering
Otto Song CS Engineering
Alex Lin Math Engineering

이 강의가 마음에 들었으면 좋겠다! 앞으로 쿼리 짤 때 여러 개의 JOIN이랑 필터를 진짜 자주 쓰게 될 거야. 거의 항상 :)

코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION