SQL JOIN 4종 쉽게 정리: INNER·LEFT·RIGHT·FULL 결과 행 수를 그림으로 이해하기 (SQLD)

SQLD를 준비하다 보면 JOIN에서 한 번은 막힙니다. INNER, LEFT, RIGHT, FULL 이름은 외웠는데 막상 결과가 몇 행인지 물으면 헷갈리죠. 사실 JOIN은 딱 하나만 이해하면 끝납니다. 두 표에서 짝이 있는 행은 붙이고, 짝이 없는 행은 버릴지 남길지 정한다는 것입니다. 이 글에서는 작은 표 두 개로 네 가지를 한 번에 정리합니다. 아래 결과는 실제로 쿼리를 실행해서 확인한 값입니다.

JOIN은 결국 무엇을 하는 걸까

JOIN은 두 표를 공통 값(보통 기본키와 외래키)으로 이어 붙여 한 줄로 보여 주는 문법입니다. 회원 표와 주문 표를 예로 들겠습니다.

회원(m)            주문(o)
id  name           oid  mid  amt
1   철수            101  1    5000
2   영희            102  1    12000
3   민수            103  3    3000
                   104  9    8000

주문 표의 mid가 회원 표의 id를 가리킵니다. 그림으로 보면 이렇습니다.

회원 표와 주문 표를 id로 짝지은 그림, 영희와 주문 104는 짝이 없음

철수는 주문이 두 건이라 선이 두 개, 민수는 한 건입니다. 영희는 주문이 없고, 주문 104번은 mid가 9인데 회원 표에 9번 회원이 없습니다. 이렇게 짝이 없는 두 행을 어떻게 다루느냐가 JOIN 종류를 나눕니다.

네 가지 JOIN은 짝 없는 행을 어떻게 다룰까

INNER, LEFT, RIGHT, FULL JOIN 결과를 비교한 벤 다이어그램
  • INNER JOIN: 짝이 있는 행만 남깁니다. 영희도, 104번 주문도 사라집니다. 결과 3행.
  • LEFT OUTER JOIN: 왼쪽(FROM 쪽) 표는 전부 남기고, 짝이 없으면 오른쪽 열을 NULL로 채웁니다. 영희가 NULL과 함께 남습니다. 결과 4행.
  • RIGHT OUTER JOIN: 오른쪽 표를 전부 남깁니다. 104번 주문이 회원 이름 NULL로 남습니다. 결과 4행.
  • FULL OUTER JOIN: 양쪽 모두 남깁니다. 영희와 104번이 둘 다 나옵니다. 결과 5행.

OUTER라는 단어는 생략해도 됩니다. LEFT JOIN이라고만 써도 같은 뜻입니다.

같은 표로 쿼리를 돌리면 결과가 어떻게 나올까

SELECT m.name, o.oid, o.amt
FROM 회원 m LEFT JOIN 주문 o ON m.id = o.mid;

LEFT JOIN 결과는 다음과 같습니다. INNER JOIN이라면 영희 줄만 빠집니다.

name  oid   amt
철수   101   5000
철수   102   12000
영희   NULL  NULL
민수   103   3000

RIGHT JOIN은 영희 줄 대신 NULL, 104, 8000 줄이 생기고, FULL JOIN은 두 줄이 모두 있어 5행이 됩니다.

시험에 자주 나오는 함정 세 가지

1) LEFT JOIN인데 왜 왼쪽 행이 사라질까. 오른쪽 표의 조건을 WHERE에 쓰면 NULL 행이 걸러져 사실상 INNER JOIN이 됩니다.

-- 영희가 사라짐 (결과 2행: 철수 101, 102)
... LEFT JOIN 주문 o ON m.id = o.mid
WHERE o.amt >= 5000;

-- 영희가 남음 (결과 4행: 철수 101, 102, 영희 NULL, 민수 NULL)
... LEFT JOIN 주문 o ON m.id = o.mid AND o.amt >= 5000;

조건을 ON에 쓰면 “짝을 맺는 조건”이고, WHERE에 쓰면 “다 붙인 뒤 거르는 조건”입니다. 순서가 달라서 결과가 달라집니다.

2) 주문이 없는 회원 찾기. LEFT JOIN 뒤에 오른쪽 기본키가 NULL인 행만 고르면 됩니다.

SELECT m.name
FROM 회원 m LEFT JOIN 주문 o ON m.id = o.mid
WHERE o.oid IS NULL;   -- 결과: 영희

3) COUNT(*)와 COUNT(컬럼)의 차이. 회원별로 세어 보면 영희는 COUNT(*)가 1, COUNT(o.oid)는 0입니다. NULL로 붙은 행도 한 줄이라 COUNT(*)는 세고, 컬럼 COUNT는 NULL을 세지 않기 때문입니다. 주문 건수를 셀 때는 COUNT(o.oid)가 맞습니다.

제 해석: 암기보다 이 순서로 풀면 덜 틀린다

제가 문제를 풀 때 쓰는 순서입니다. 먼저 ON 조건으로 짝 지어지는 선을 그립니다. 다음으로 짝 없는 행이 어느 쪽에 있는지 표시합니다. 마지막으로 LEFT면 왼쪽, RIGHT면 오른쪽, FULL이면 양쪽의 짝 없는 행을 살려 줄 수를 셉니다. 벤 다이어그램은 개념 이해용으로는 좋지만, 한 행이 여러 행과 짝이 되는 경우(철수의 주문 두 건)는 원 그림에 드러나지 않습니다. 줄 수를 묻는 문제에서는 꼭 선을 그려 보는 쪽이 안전합니다.

시험 직전 체크리스트

  1. INNER는 3행, LEFT와 RIGHT는 4행, FULL은 5행이 되는 이유를 말로 설명할 수 있는가
  2. 오른쪽 표의 조건을 WHERE에 쓰면 LEFT JOIN이 INNER처럼 동작하는 이유를 아는가
  3. “짝 없는 행 찾기” 문제에서 IS NULL을 오른쪽 기본키에 거는가
  4. COUNT(*)와 COUNT(컬럼)이 NULL 행에서 어떻게 다른지 아는가
  5. DBMS에 따라 문법이 다르다는 점을 기억하는가. 예를 들어 MySQL은 FULL OUTER JOIN을 지원하지 않고, Oracle은 예전 방식의 (+) 표기도 씁니다.

안내: 예시 표는 설명을 위해 직접 만든 가상의 데이터이며, 결과는 SQLite에서 실행해 확인했습니다. 실제 시험 문제와 같지 않을 수 있으니 공식 기출과 함께 학습하세요.

Leave a Comment