본문 바로가기

DB

[DB] 외부 조인 (OUTER JOIN), 셀프 조인 (SELF JOIN), 크로스 조인 (CROSS JOIN)

🧩 외부 조인 (OUTER JOIN): 짝이 없는 데이터 찾기

 

내부 조인(INNER JOIN)은 양쪽 테이블에 모두 데이터가 존재하는, 즉 짝이 맞는 데이터(교집합)만 보여준다.

하지만 실무에서는 "가입은 했지만 한 번도 주문하지 않은 고객"이나 "등록은 했지만 한 번도 팔리지 않은 상품"처럼,

한쪽 테이블에는 데이터가 있지만, 다른 쪽에는 없는 소외된 데이터를 찾아야 할 때가 많다.

이때 사용하는 것이 외부 조인(OUTER JOIN)이다.

 

외부 조인은 조인 조건에 맞지 않더라도, 기준이 되는 테이블의 모든 데이터를 결과에 포함시킨다.

이때 짝이 맞는 데이터가 없는 쪽의 열은 NULL 값으로 채워진다.

 


🧩 LEFT JOIN vs RIGHT JOIN

 

외부 조인은 어느 테이블을 기준으로 삼느냐에 따라 둘로 나뉜다.

 

  • LEFT JOIN (왼쪽 외부 조인)
    • FROM 절에 있는 왼쪽 테이블이 기준이 된다.
    • 왼쪽 테이블의 모든 행을 일단 결과에 포함시키고, ON 조건에 맞는 오른쪽 테이블의 데이터를 찾아 옆에 붙인다.
  • RIGHT JOIN (오른쪽 외부 조인)
    • JOIN 절에 있는 오른쪽 테이블이 기준이 된다.
    • 오른쪽 테이블의 모든 행을 일단 결과에 포함시키고, ON 조건에 맞는 왼쪽 테이블의 데이터를 찾아 옆에 붙인다.

 

실무에서는 분석 기준이 되는 테이블을 FROM 절에 먼저 쓰고, LEFT JOIN으로 필요한 정보를 붙여나가는 방식을 선호한다.

RIGHT JOIN은 테이블의 순서를 바꾸면 언제나 LEFT JOIN으로 동일하게 표현할 수 있기 때문에 잘 사용되지 않는다.

-- 한 번도 주문하지 않은 고객 찾기
-- 모든 고객을 기준으로 주문 내역을 붙여봐야 하므로, users 테이블을 기준으로 LEFT JOIN을 사용
SELECT
    u.name,
    o.order_id
FROM
    users u
LEFT JOIN
    orders o ON u.user_id = o.user_id
WHERE
    o.order_id IS NULL; -- 주문 ID가 NULL인 고객 == 주문하지 않은 고객

 


✅ 조인의 특징: 행의 개수는 어떻게 변할까?

 

조인을 할 때 결과의 행 수가 기준 테이블과 같을 수도 있고, 더 늘어날 수도 있다.

이 원리를 이해하는 것은 집계 함수를 사용할 때 매우 중요하다.

 

우선, 기본 키(PK)는 테이블 내에서 절대 중복될 수 없다. 하지만 외래 키(FK)는 여러 번 중복될 수 있다.

즉, 부모 테이블의 기본 키를 참조하는 자식 테이블의 외래 키는 여러 개일 수 있다.

 

따라서 부모 테이블과 자식 테이블의 조인 방향에 따라 다음과 같이 결과의 행 수가 달라진다.

 

  • 행 개수 유지 (To-One 관계):
    • 자식 테이블 → 부모 테이블로 조인할 때
    • 예: FROM orders JOIN users
      • 주문(자식)은 반드시 단 한 명의 고객(부모)에게 속한다.
      • 즉, 자식 테이블의 각 행은 부모 테이블의 단 하나의 행과만 연결된다.
      • 따라서 기준 테이블인 orders의 행 개수가 그대로 유지된다.
  • 행 개수 증가 가능 (To-Many 관계):
    • 부모 테이블 → 자식 테이블로 조인할 때
    • 예: FROM users JOIN orders
      • 한 명의 고객(부모)은 여러 개의 주문(자식)을 가질 수 있다.
      • 이 경우, 부모 행(고객 정보)이 자식 행(주문 건수)만큼 복제되어 전체 행의 수가 늘어날 수 있다.

 


🧩 셀프 조인 (SELF JOIN)

 

SELF JOIN은 새로운 명령어가 아니라, 하나의 테이블을 자기 자신과 조인하는 기법을 말한다.

테이블 내에 계층적인 관계가 있을 때 사용한다. (예: 직원의 상사 정보)

 

핵심 원리는 테이블 별칭(Alias)을 사용해 하나의 테이블을 두 개의 다른 가상 테이블처럼 다루는 것이다. (예: 직원(e)과 상사(m))

SELECT
    e.name AS employee_name, -- 직원 이름
    m.name AS manager_name -- 상사 이름
FROM
    employees e
LEFT JOIN -- 상사가 없는 최상위 직원도 포함하기 위해 LEFT JOIN 사용
    employees m ON e.manager_id = m.employee_id;

 


🧩 크로스 조인 (CROSS JOIN)

 

CROSS JOINON 조건 없이 한 테이블의 모든 행을 다른 테이블의 모든 행과 가능한 모든 조합으로 연결하는 조인이다.

그 결과는 카테시안 곱 (Cartesian Product)이라고 불린다.

 

주로 상품의 사이즈, 색상 등 모든 옵션 조합을 담은 마스터 데이터를 생성할 때 유용하게 사용된다.

SELECT
    s.size,
    c.color
FROM
    sizes s
CROSS JOIN
    colors c;

 

⚠️ 실무 경고: 데이터가 많은 테이블에 CROSS JOIN을 잘못 사용하면 결과 행이 기하급수적으로 늘어나 서버에 심각한 부하를 줄 수 있으므로 매우 신중하게 사용해야 한다.