Skip to content
난이도 면접 빈출문제은행 4

조인 종류와 작성 ​

조인(join)은 두 테이블의 행을 조건으로 짝지어 한 행으로 이어 붙이는 연산이다. 어떤 조인을 쓰느냐에 따라 짝이 없는 행을 버릴지 남길지가 달라진다. 이 문서는 조인 종류마다 어떤 행이 남는지와, MySQL에 없는 FULL OUTER JOIN을 대신 만드는 법을 다룬다. MySQL이 조인을 어떤 방법으로 실행하는지는 조인 최적화에서 본다.

조인 종류 ​

아래 예시는 회원 users(id, name)과 주문 orders(id, user_id, amount)를 쓴다. 주문이 없는 회원도 있다고 하자.

종류남는 행짝이 없으면
INNER JOIN양쪽 모두 짝이 있는 행버린다
LEFT JOIN왼쪽 테이블의 모든 행오른쪽 칼럼을 NULL로 채운다
RIGHT JOIN오른쪽 테이블의 모든 행왼쪽 칼럼을 NULL로 채운다
CROSS JOIN양쪽 행의 모든 조합조건 자체가 없다
  • 내부 조인(inner join)인 INNER JOIN은 조건이 맞는 짝만 돌려준다. "주문한 적 있는 회원과 그 주문"이 여기에 해당한다.
  • 외부 조인(outer join)은 한쪽 테이블의 행을 짝이 없어도 모두 남기는 조인이다. LEFT JOIN은 왼쪽을, RIGHT JOIN은 오른쪽을 남긴다. 둘은 테이블 순서만 바꾸면 같은 뜻이므로, 읽기 쉽고 다른 DB로 옮기기 쉽게 LEFT JOIN으로 통일하는 편이 좋다.
  • **CROSS JOIN**은 조건 없이 모든 조합을 만든다. 이렇게 만든 조합을 카티전 곱(Cartesian product)이라 하며, 1,000행과 1,000행이면 100만 행이 된다. 날짜 목록과 상품 목록으로 빈 칸 없는 보고서 틀을 만들 때처럼 일부러 쓰는 경우 말고는 대개 조건을 빠뜨린 실수다.
  • 셀프 조인(self join)은 같은 테이블을 별칭(alias, employees e처럼 FROM에서 테이블 뒤에 붙이는 짧은 이름) 두 개로 불러 자기 자신과 잇는 것이다. 직원 테이블에서 e.manager_id = m.id로 직원과 상사를 한 행에 놓는 식이다. 별칭이 없으면 어느 쪽 칼럼인지 구분할 수 없으므로 별칭이 필수다.

MySQL에서 JOIN, INNER JOIN, CROSS JOIN은 문법상 같은 것으로 취급된다. 조건을 ON에 주면 내부 조인, 안 주면 카티전 곱이 된다. 표준 SQL에서는 셋을 구분하므로, 의도가 드러나게 조건이 있으면 INNER JOIN ... ON, 없으면 CROSS JOIN으로 쓴다. 쉼표로 테이블을 나열하는 옛 문법(FROM a, b WHERE ...)은 JOIN보다 나중에 묶인다. 그래서 FROM a, b JOIN c ON a.x = c.x는 a, (b JOIN c ON ...)으로 해석되고, 괄호 안의 ON은 a를 볼 수 없어 칼럼을 모른다는 오류가 난다. 한 문장에서는 한 가지 문법만 쓴다.

FULL OUTER JOIN 대체 ​

FULL OUTER JOIN은 양쪽의 짝 없는 행을 모두 남기는 조인인데, MySQL은 지원하지 않는다. 두 외부 조인의 결과를 UNION ALL로 이어 붙여 만든다. UNION ALL은 두 SELECT의 결과 행을 위아래로 그대로 합치고, UNION은 합친 뒤 똑같은 행을 하나만 남긴다. 아래 a·b는 임의의 두 테이블이고 b.a_id가 a.id를 가리킨다.

sql
SELECT a.id, b.id FROM a LEFT JOIN b ON a.id = b.a_id
UNION ALL
SELECT a.id, b.id FROM a RIGHT JOIN b ON a.id = b.a_id
WHERE a.id IS NULL;   -- 오른쪽에만 있는 행만 추가

첫 번째 SELECT는 왼쪽 테이블의 모든 행과 그 짝을 만든다. 두 번째 SELECT의 RIGHT JOIN은 짝 없는 오른쪽 행의 왼쪽 칼럼을 NULL로 채우므로, a.id IS NULL을 걸면 이미 나온 짝 있는 행은 빠지고 오른쪽에만 있는 행만 남는다. 흔히 LEFT JOIN ... UNION ... RIGHT JOIN으로 쓰기도 하지만, UNION은 중복 행을 없애므로 원래부터 똑같은 행이 두 번 있어야 하는 결과까지 하나로 줄여 버린다. 위처럼 UNION ALL로 붙이고 겹치는 부분은 조건으로 빼는 쪽이 정확하다.

이어지는 내용은 조인 종류와 작성 2에서 다룬다. 외부 조인에서 조건을 ON에 쓰느냐 WHERE에 쓰느냐에 따라 결과가 달라지는 함정, 외부 조인 뒤 집계, 짝이 있는지만 보는 세미 조인(semi-join)과 짝이 없는 행만 남기는 안티 조인(anti-join) 작성법을 본다.

면접 포인트 ​

  • "LEFT JOIN과 INNER JOIN 차이?" → 짝 없는 왼쪽 행을 NULL로 채워 남기느냐 버리느냐.
  • "CROSS JOIN은 언제 쓰나?" → 모든 조합(카티전 곱)이 필요할 때만. 대개는 조건을 빠뜨린 실수다. MySQL에서 ON 없는 JOIN도 카티전 곱이다.
  • "MySQL에서 FULL OUTER JOIN은?" → 없다. LEFT JOIN + UNION ALL + 오른쪽에만 있는 행(RIGHT JOIN ... WHERE 왼쪽 IS NULL).

관련 문서