SQL 조인 이해하기: 시각적 가이드
Olivia Novak
Dev Intern · Leapcell

SQL 조인 소개
관계형 데이터베이스의 세계에서는 정규화된 설계를 달성하고 중복을 줄이며 데이터 무결성을 향상시키기 위해 데이터가 여러 테이블에 걸쳐 구성되는 경우가 많습니다. 이러한 구조는 저장에 매우 효율적이지만, 이러한 별도의 테이블에 걸쳐 있는 정보를 검색하고 분석해야 하는 수많은 시나리오가 있습니다. 이것이 바로 SQL JOIN 연산이 필수적인 이유입니다. 조인은 관계형 데이터베이스 쿼리의 초석으로, 두 개 이상의 테이블 간의 관련 열을 기반으로 행을 지능적으로 결합할 수 있게 해줍니다. 조인에 대한 확고한 이해 없이는 복잡한 데이터 세트에서 의미 있는 통찰력을 추출하는 것이 불가능하지는 않더라도 매우 어려운 과제가 될 것입니다. 이 가이드에서는 가장 일반적인 SQL JOIN 유형인 INNER JOIN, LEFT JOIN, FULL OUTER JOIN, CROSS JOIN을 시각적으로 살펴보고, 각 조인의 동작 방식을 명확히 하고 각 조인을 효과적으로 사용해야 할 때와 방법을 보여줍니다.
조인 이해를 위한 핵심 개념
각 조인 유형의 세부 사항을 살펴보기 전에 이 가이드 전체에서 사용할 몇 가지 기본 용어를 정의해 보겠습니다.
- 테이블(Table): 특정 유형의 정보(예:
Customers,Orders)를 보유하도록 설계된 행과 열로 구성된 구조화된 데이터 세트입니다. - 행(Row / Record): 테이블의 단일 항목으로, 특정 개체에 대한 관련 데이터의 완전한 집합을 나타냅니다.
- 열(Column / Field): 테이블의 각 항목에 대한 특정 속성 또는 정보 조각(예:
customer_id,order_date)입니다. - 기본 키(Primary Key / PK): 테이블의 각 행을 고유하게 식별하는 열(또는 열 집합)입니다. NULL 값을 포함할 수 없으며 고유해야 합니다.
- 외래 키(Foreign Key / FK): 한 테이블의 열(또는 열 집합)으로, 다른 테이블의 기본 키를 참조합니다. 외래 키는 두 테이블 간의 데이터 링크를 설정하고 적용합니다.
- 조인 조건(Join Condition): 일반적으로
ON뒤에 오는 절로, 두 테이블이 어떻게 관련되어야 하는지를 지정하며, 일반적으로 한 테이블의 외래 키를 다른 테이블의 기본 키와 일치시킵니다.
예제에서는 두 개의 간단한 테이블인 Customers와 Orders를 사용합니다.
Customers 테이블:
| customer_id | customer_name |
|---|---|
| 1 | Alice |
| 2 | Bob |
| 3 | Charlie |
| 4 | David |
Orders 테이블:
| order_id | customer_id | order_date | amount |
|---|---|---|---|
| 101 | 1 | 2023-01-05 | 150.00 |
| 102 | 2 | 2023-01-06 | 200.00 |
| 103 | 1 | 2023-01-07 | 50.00 |
| 104 | 5 | 2023-01-08 | 300.00 |
| 105 | 2 | 2023-01-09 | 75.00 |
| 106 | NULL | 2023-01-10 | 120.00 |
customer_id가 Customers 테이블의 기본 키이고 Orders 테이블의 외래 키임을 알 수 있습니다. 고객 ID 5(존재하지 않음)에 대한 주문(104)과 고객 ID가 NULL인 주문(106)이 있습니다. 이는 다양한 조인 동작을 설명하는 데 도움이 될 것입니다.
INNER JOIN: 교집합
INNER JOIN은 가장 일반적인 유형의 조인입니다. 지정된 조인 조건에 따라 두 테이블 모두에서 일치하는 값을 가진 행만 반환합니다. 이를 두 집합의 교집합을 찾는 것으로 생각할 수 있습니다. 한 테이블의 행이 다른 테이블에 해당 일치가 없으면 결과에서 제외됩니다.
시각적 표현:
서로 겹치는 두 개의 원을 상상해 보세요. INNER JOIN은 겹치는 영역을 반환합니다.
Customers
+-----------+
| Alice |
| Bob | (Overlap)
| Charlie | <--- INNER JOIN result
| David |
+-----------+
+-----------+
| Order 1 |
| Order 2 |
| Order 3 |
| Order 4 |
| Order 5 |
+-----------+
Orders
SQL 예제:
SELECT C.customer_id, C.customer_name, O.order_id, O.order_date, O.amount FROM Customers C INNER JOIN Orders O ON C.customer_id = O.customer_id;
결과:
| customer_id | customer_name | order_id | order_date | amount |
|---|---|---|---|---|
| 1 | Alice | 101 | 2023-01-05 | 150.00 |
| 2 | Bob | 102 | 2023-01-06 | 200.00 |
| 1 | Alice | 103 | 2023-01-07 | 50.00 |
| 2 | Bob | 105 | 2023-01-09 | 75.00 |
설명:
- 고객 'Alice'(ID 1)는 두 개의 주문(101, 103)이 있으므로 둘 다 표시됩니다.
- 고객 'Bob'(ID 2)은 두 개의 주문(102, 105)이 있으므로 둘 다 표시됩니다.
- 고객 'Charlie'(ID 3) 및 'David'(ID 4)는 일치하는 주문이 없으므로 제외됩니다.
- 주문 104(고객 ID 5) 및 주문 106(NULL 고객 ID)은 일치하는 고객이 없으므로 제외됩니다.
사용 사례: 주문을 넣은 고객의 세부 정보 검색.
LEFT JOIN (또는 LEFT OUTER JOIN): 왼쪽의 모든 것, 오른쪽의 일치하는 것
A LEFT JOIN(또는 LEFT OUTER JOIN)은 왼쪽 테이블의 모든 행과 오른쪽 테이블의 일치하는 행을 반환합니다. 왼쪽 테이블의 행에 대한 일치 항목이 없으면 오른쪽 테이블의 열에는 NULL 값이 포함됩니다.
시각적 표현: 왼쪽 원이 완전히 포함되고 오른쪽 원의 겹치는 부분을 상상해 보세요.
Customers
+-----------+
| Alice |
| Bob | <--- LEFT JOIN result
| Charlie |
| David |
+-----------+
+-----------+
| Order 1 |
| Order 2 |
| Order 3 |
| Order 4 |
| Order 5 |
+-----------+
Orders
SQL 예제:
SELECT C.customer_id, C.customer_name, O.order_id, O.order_date, O.amount FROM Customers C LEFT JOIN Orders O ON C.customer_id = O.customer_id;
결과:
| customer_id | customer_name | order_id | order_date | amount |
|---|---|---|---|---|
| 1 | Alice | 101 | 2023-01-05 | 150.00 |
| 1 | Alice | 103 | 2023-01-07 | 50.00 |
| 2 | Bob | 102 | 2023-01-06 | 200.00 |
| 2 | Bob | 105 | 2023-01-09 | 75.00 |
| 3 | Charlie | NULL | NULL | NULL |
| 4 | David | NULL | NULL | NULL |
설명:
- 모든 고객(Alice, Bob, Charlie, David)이 포함됩니다.
- 주문이 없는 고객 'Charlie'(ID 3) 및 'David'(ID 4)의 경우
Orders열에NULL값이 표시됩니다. - 주문 104(고객 ID 5) 및 주문 106(NULL 고객 ID)은
Customers테이블에 일치하는customer_id가 없으며Customers가 왼쪽 테이블이므로 포함되지 않습니다.
사용 사례: 주문을 전혀 하지 않은 고객을 포함하여 모든 고객과 그들이 주문한 주문을 찾는 것. 이는 비활성 고객을 식별하는 데 유용합니다.
FULL OUTER JOIN (또는 OUTER JOIN): 양쪽 모두의 모든 것
A FULL OUTER JOIN(또는 일부 SQL 방언에서는 간단히 OUTER JOIN이지만 FULL OUTER JOIN이 표준임)은 왼쪽 또는 오른쪽 테이블 중 하나에 일치 항목이 있을 때 모든 행을 반환합니다. 일치 항목이 없으면 일치하지 않는 쪽에는 NULL 값이 포함됩니다. 이 조인은 LEFT JOIN과 RIGHT JOIN의 결과를 효과적으로 결합합니다.
시각적 표현: 두 원이 완전히 포함되고 겹치는 부분이 한 번 나타나는 것을 상상해 보세요.
Customers
+-----------+
| Alice |
| Bob |
| Charlie | <--- FULL OUTER JOIN result
| David |
+-----------+
+-----------+
| Order 1 |
| Order 2 |
| Order 3 |
| Order 4 |
| Order 5 |
+-----------+
Orders
SQL 예제:
SELECT C.customer_id, C.customer_name, O.order_id, O.order_date, O.amount FROM Customers C FULL OUTER JOIN Orders O ON C.customer_id = O.customer_id;
결과:
| customer_id | customer_name | order_id | order_date | amount |
|---|---|---|---|---|
| 1 | Alice | 101 | 2023-01-05 | 150.00 |
| 1 | Alice | 103 | 2023-01-07 | 50.00 |
| 2 | Bob | 102 | 2023-01-06 | 200.00 |
| 2 | Bob | 105 | 2023-01-09 | 75.00 |
| 3 | Charlie | NULL | NULL | NULL |
| 4 | David | NULL | NULL | NULL |
| NULL | NULL | 104 | 2023-01-08 | 300.00 |
| NULL | NULL | 106 | 2023-01-10 | 120.00 |
설명:
- 모든 고객(Alice, Bob, Charlie, David)이 포함됩니다.
- 주문 101, 102, 103, 105는 해당 고객과 일치합니다.
Charlie와David는 주문이 없으므로 주문 정보가NULL입니다.- 주문 104(고객 ID 5,
Customers에 없음)와 주문 106(NULL 고객 ID)은 포함되지만, 일치하는 고객이 없으므로Customers열은NULL입니다.
사용 사례: 두 테이블의 모든 데이터를 보고 잠재적인 데이터 불일치(예: 고객이 없는 주문 또는 주문이 없는 고객)를 강조하려는 관계를 분석하는 데 유용합니다.
CROSS JOIN: 데카르트 곱
A CROSS JOIN은 두 테이블의 데카르트 곱을 반환합니다. 즉, 첫 번째 테이블의 모든 행이 두 번째 테이블의 모든 행과 결합됩니다. CROSS JOIN에 대한 조인 조건은 지정되지 않습니다.
시각적 표현: 두 개의 원이 나란히 있고 첫 번째 원의 모든 지점을 두 번째 원의 모든 지점과 연결하는 선이 있는 것을 상상해 보세요.
Customers Orders
+-----------+ +-----------+
| Alice | | Order 1 |
| Bob | | Order 2 |
| Charlie | | Order 3 |
| David | | Order 4 |
+-----------+ | Order 5 |
+-----------+
(모든 고객 행이 모든 주문 행과 결합됨)
SQL 예제:
SELECT C.customer_id, C.customer_name, O.order_id, O.order_date, O.amount FROM Customers C CROSS JOIN Orders O;
결과 (부분 - 총 4 고객 * 6 주문 = 24 행):
| customer_id | customer_name | order_id | order_date | amount |
|---|---|---|---|---|
| 1 | Alice | 101 | 2023-01-05 | 150.00 |
| 1 | Alice | 102 | 2023-01-06 | 200.00 |
| 1 | Alice | 103 | 2023-01-07 | 50.00 |
| ... | ... | ... | ... | ... |
| 4 | David | 104 | 2023-01-08 | 300.00 |
| 4 | David | 105 | 2023-01-09 | 75.00 |
| 4 | David | 106 | 2023-01-10 | 120.00 |
설명:
- 4명의 고객 각각이 6개의 주문 각각과 결합되어 총 24개의 행이 생성됩니다.
- 예를 들어, 'Alice'는 6개의 모든 주문과 쌍을 이루며, 이는 Bob, Charlie, David에 대해서도 반복됩니다.
사용 사례: CROSS JOIN은 매우 큰 결과 세트를 생성할 수 있으므로 일반적인 데이터 검색에는 덜 일반적입니다. 주요 용도는 다음과 같습니다.
- 데이터 집합 간의 모든 가능한 조합 생성(예: 가능한 모든 날짜와 가능한 모든 시간 슬롯의 캘린더 생성).
- 대규모 데이터 세트를 시뮬레이션해야 하는 테스트 목적.
- 때로는 특정 통계 분석(예: 총 백분율 계산)을 달성하기 위해 다른 절과 함께 사용됩니다.
결론
SQL JOIN은 관계형 데이터베이스 쿼리의 중추이며, 분산된 데이터를 의미 있는 결과로 통합하는 강력한 메커니즘을 제공합니다. INNER JOIN은 공통 영역을 제공하고, LEFT JOIN은 왼쪽 테이블을 우선하며, FULL OUTER JOIN은 양쪽의 모든 것을 포함하고, CROSS JOIN은 가능한 모든 쌍을 생성합니다. 이러한 차이점을 이해하고 각 조인을 적용해야 할 때를 아는 것은 관계형 데이터베이스 작업을 하는 모든 사람에게 중요하며, 데이터의 전체 잠재력을 발휘하는 정확하고 효율적인 쿼리를 작성할 수 있게 해줍니다. 이러한 조인을 마스터하면 가장 복잡한 데이터베이스 스키마에서 나온 복잡한 패턴과 통찰력을 추출하는 것을 마스터하게 될 것입니다.