Join
1. 조인이 필요한 이유
- 왜 불편하게 데이터를 여러 테이블에 나누어 저장하는 걸까?
- 차라리 처음부터 하나의 큰 테이블에 주문 정보, 고객 정보, 상품 정보를 모두 담아두면 편하지 않았을까?
2. 만약 모든 데이터를 하나의 테이블에 저장하면?
- 궁금증을 해결하기 위해,
users,products,orders테이블을 모두 제거하고, 이 테이블의 필드를 하나로 합친all_in_one테이블을 상상해 보자. - 당장은 편해 보인다. 하지만 이런 방식은 실무에서 재앙을 불러온다.
- 다음과 같은 심각한 문제들이 발생하기 때문이다.
2.1 데이터베이스 이상 현상들
데이터 중복 (Redundancy)
- '션' 고객이 상품을 100번 주문했다고 생각해 보자.
- 그의 이름, 이메일, 주소 정보가 100번이나 불필요하게 반복 저장된다.
- 이건 매우 큰 저장 공간의 낭비다.
갱신 이상 (Update Anomaly)
- 만약 '션' 고객이 이메일 주소를 변경했다고 가정해 보자.
- 우리는 '션'이 주문한 100개의 주문 데이터를 모두 찾아서, 이메일 정보를 일일이 새로운 주소로 변경해야 한다.
- 만약 실수로 단 하나라도 누락한다면? 어떤 주문에서는 고객의 이메일이 예전 주소로, 다른 주문에서는 새 주소로 저장되어 데이터의 일관성이 깨져버린다.
- 어떤 정보가 진짜인지 믿을 수 없게 되는 것이다.
삽입 이상 (Insertion Anomaly)
- 우리 쇼핑몰에 아직 아무도 주문하지 않은 새로운 상품 '초경량 노트북'을 등록하고 싶다.
- 하지만 이 테이블 구조에서는 '주문'이 발생해야만 데이터를 추가할 수 있다.
- 주문한 사람이 없으니, 상품 정보조차 등록할 수 없는 상황이 발생한다.
삭제 이상 (Deletion Anomaly)
- '이순신' 고객이 딱 한 번 주문한 기록이 있다고 하자.
- 만약 회사 정책상 이 주문 기록을 삭제해야 한다면 어떻게 될까?
- 주문 데이터를 삭제하는 순간, '이순신' 고객의 이름, 이메일, 주소 정보까지 데이터베이스에서 영원히 사라져 버릴 수 있다.
- 우리는 단지 주문 내역 하나를 지웠을 뿐인데, 소중한 고객 정보까지 잃게 되는 것이다.
정규화의 필요성
- 이러한 문제들 때문에 우리는 데이터베이스를 설계할 때 **정규화(Normalization)**라는 과정을 거친다.
- 정규화는 데이터의 중복을 최소화하고, 데이터의 일관성을 해치는 '이상 현상'들을 방지하기 위해 데이터를 논리적인 단위로 분리하는 과정이다.
- 우리가
users,products,orders로 테이블을 나눈 것이 바로 이 정규화의 결과물이다. - 데이터베이스 정규화 참고
2.2 그래서 조인이 필요하다
- 이제 우리는 왜 데이터를 분리해서 저장하는지 이해했다.
- 데이터의 중복을 막고, 일관성을 지키기 위해서다. 즉, 데이터를 '잘 관리하기 위해서'다.
- 하지만 잘 관리하기 위해 흩어놓은 데이터에서 의미 있는 정보를 얻으려면, 이 흩어진 조각들을 다시 합쳐야만 한다.
- "어떤 고객이 어떤 상품을 주문했는지"와 같은 통합된 보고서를 만들기 위해, 분리된 테이블들을 다시 연결해야 하는 것이다.
이때 사용하는 기술이 바로 조인(JOIN)이다.
- 조인은 두 개 이상의 테이블을 특정 컬럼을 기준으로 연결하여, 마치 처음부터 하나의 테이블이었던 것처럼 보여주는 기능이다.
- 보통 테이블을 설계할 때 연결고리로 사용하는
기본 키(Primary Key)와외래 키(Foreign Key)를 사용해 이들을 합친다. orders테이블의user_id외래 키(FK)는users테이블의user_id기본 키(PK)와 연결된다.orders테이블의product_id외래 키(FK)는products테이블의product_id기본 키(PK)와 연결된다.- 조인은 데이터 정규화(분리)를 통해 얻는 일관성과 효율성의 장점은 그대로 유지하면서, 우리가 원하는 통합된 정보를 얻을 수 있게 해주는, 데이터 분리와 통합을 완성하는 기술이다.
3. 내부 조인 (INNER JOIN)
- 데이터의 일관성과 효율성을 위해 테이블을 분리(정규화)하며, 이렇게 분리된 테이블을 다시 합쳐 의미 있는 정보를 얻기 위해 조인(
JOIN)이 필요하다는 사실을 깨달았다.
3.1 내부 조인의 개념
- 내부 조인(
INNER JOIN)은 두 테이블을 연결할 때, 양쪽 테이블에 모두 공통으로 존재하는 데이터만을 결과로 보여준다. - 기준이 되는 컬럼(예:
orders.user_id와users.user_id)의 값이 서로 일치하는 행들만 짝을 지어주는 것이다.
3.2 내부 조인 문법
SELECT 컬럼1, 컬럼2, ...
FROM 테이블A
INNER JOIN 테이블B
ON 테이블A.연결컬럼 = 테이블B.연결컬럼;
FROM: 기준이 되는 첫 번째 테이블을 지정한다.INNER JOIN: 연결할 두 번째 테이블을 지정한다.ON: 조인에서 가장 중요한 부분이다. 두 테이블을 어떤 조건으로 연결할지 명시하는 연결고리다.ON절의 조건이 참(true)이 되는 행들만 결과에 포함된다.
3.3 조인 작동 순서
- 결제 완료된 주문의 고객명과 주문 날짜가 어떤 순서로 조회된 것인지 조인이 작동하는 논리적인 순서를 알아보자.
SELECT
users.user_id,
users.name,
orders.order_date
FROM orders
INNER JOIN users ON orders.user_id = users.user_id
WHERE orders.status = 'COMPLETED';
- 데이터베이스는 이 쿼리를 다음과 같은 논리적인 순서로 처리한다.
1. FROM / JOIN
- 가장 먼저
FROM절의orders테이블과INNER JOIN으로 연결된users테이블을 연결하기 위해ON절에 명시된orders.user_id = users.user_id조건을 만족하는 행들을 결합하여 하나의 큰 가상 테이블을 생성한다.
2. WHERE
JOIN을 통해 생성된 가상 테이블에서WHERE절의 조건인orders.status = 'COMPLETED'를 만족하는 행들만 필터링한다.- 즉,
COMPLETED상태의 주문 데이터만 남게 된다.
3. SELECT
- 마지막으로, 필터링된 결과에서
SELECT절에 명시된users.user_id,name과order_date컬럼을 추출하여 최종 결과를 반환한다.
논리적 처리 순서 요약
JOIN을 통해 두 테이블을 먼저 합친 가상의 테이블을 만든 후,WHERE절의 조건에 따라 필요한 행을 걸러낸다.- 그리고 최종적으로 원하는 필드를
SELECT로 선택하는 순서로 작동한다. FROM/JOIN (테이블 결합)→WHERE (조건 필터링)→SELECT (컬럼 선택)
3.4 쿼리 최적화기 (Query Optimizer)
- 사용자와 데이터베이스 간의 논리적 순서는 일종의 약속이지만, 데이터베이스 내부의 **쿼리 최적화기(Query Optimizer)**는 쿼리를 더 효율적인 방식으로 실행한다.
- 예를 들어,
orders테이블에서COMPLETED상태의 행만 먼저 선택한 다음, 남은 행을 기준으로users테이블과 조인하는 방식으로 진행하면 조인 대상이 줄어들어 성능이 더 최적화될 수 있다. - 쿼리 최적화기를 통해 실제 물리적인 실행 순서는 달라질 수 있지만 어떻게 작동하든 최종 결과는 논리적인 순서와 동일하다.
- 하지만 데이터베이스의 최적화 방식을 잘 이해하면 같은 결과를 얻으면서도 조회 성능을 최적화할 수 있다.
3.5 조인과 집합
- 내부 조인을 이해하는 또 다른 방법은 바로 '집합'의 관점에서 바라보는 것이다.
- 학창 시절 수학 시간에 배운 벤 다이어그램을 떠올리면 아주 쉽게 이해할 수 있다.
- 어려운 수학을 이야기하는 것이 아니다! 단순한 동그라미 그리기 관점으로 이해하자!
- 내부 조인(
INNER JOIN)은 두 테이블의 교집합을 찾는 것과 같다. - 두 집합(테이블)에서 공통된 원소(연결 컬럼 의 값이 일치하는 데이터)만을 결과로 반환한다.
- A 집합:
orders테이블에 있는 모든 사용자들의user_id집합 - B 집합:
users테이블에 있는 모든user_id집합
- A 집합:
- 벤 다이어그램을 보면 내부 조인(
INNER JOIN)의 이름을 왜 내부라고 지었는지 알 수 있다.- 내부 조인은 벤 다이어그램에서 둘의 겹친 영역인 교집합 영역을 말한다.
- 교집합 영역은 벤 다이어그램에서 내부에 있는 데이터를 뜻한다.
- 이후에 설명할 외부 조인(
OUTER JOIN)은 교집합 영역의 밖(OUTER)의 행까지 포함한다는 의미이다.
- 결론적으로,
INNER JOIN은 어느 한쪽에만 데이터가 존재하는 경우는 결과에 포함시키지 않고, 양쪽 모두에 명확하게 연결고리가 있는 데이터만을 짝지어 보여준다.
3.6 내부 조인과 조인 방향
- 내부 조인은 양방향이다.
- A 테이블과 B 테이블이 있다고 하면, A → B로 조인할 수 있다면 반대로 B → A로 조인할 수 있다.
- 그리고 그 결과는 항상 동일하다.
왜 결과가 동일할까?
- 내부 조인은 두 테이블 간의 교집합을 찾는 연산이기 때문이다.
A와 B의 교집합과B와 A의 교집합이 같은 것과 같은 원리다.
실무 팁: 조인 순서는 언 제 중요할까?
- 내부 조인에서는 결과가 같으므로 어떤 순서로 작성해도 무방하다.
- 하지만 쿼리를 읽는 사람의 입장에서 어떤 데이터가 중심이 되는가에 따라 순서를 정하면 가독성이 높아진다.
- 주문 목록을 중심으로 고객 정보를 추가하고 싶다면
FROM orders JOIN users - 고객 목록을 중심으로 주문 정보를 조회하고 싶다면
FROM users JOIN orders
- 주문 목록을 중심으로 고객 정보를 추가하고 싶다면
3.7 내부 조인의 한계
- 그런데 여기서 또 다른 질문이 생긴다.
- "그렇다면, 우리 쇼핑몰에 가입은 했지만 아직 한 번도 주문하지 않은 고객은 어떻게 찾아낼 수 있을까?"
- 내부 조인(
INNER JOIN)은 양쪽에 모두 데이터가 있는 경우만 보여주기 때문에 이 질문에는 답할 수 없다. - 이 문제를 해결하기 위해 외부 조인(
OUTER JOIN)에 대해 알아보겠다.
4. 외부 조인 (OUTER JOIN)
- 내부 조인(
INNER JOIN)을 통해 우리는 양쪽 테이블에 모두 존재하는, 짝이 맞는 데이터들을 성공적으로 연결했다. - 하지만 실무에서는 종종 짝이 없는, 소외된 데이터를 찾아야 할 때가 있다.
- 위에서 던졌던 질문을 다시 떠올려 보자.
- "우리 쇼핑몰에 가입은 했지만, 아직 한 번도 주문하지 않은 고객은 누구일까?"
- "야심차게 출시했지만, 아직 단 한 번도 팔리지 않은 비운의 상품은 무엇일까?"
- 이 질문들에 내부 조인은 답할 수 없다.
- 왜냐하면 내부 조인은 주문 기록이 있는 고객, 판매 기록이 있는 상품, 즉
orders테이블과 짝이 맞는 데이터만 보여주기 때문이다. - 주문한 적 없는 고객이나 팔린 적 없는 상품은
orders테이블에 짝이 없으므로 결과에서 아예 누락된다.
4.1 내부 조인의 한계 확인
users 테이블 조회
SELECT user_id, name, email FROM users;
실행 결과
| user_id | name | |
|---|---|---|
| 1 | 션 | sean@example.com |
| 2 | 네이트 | nate@example.com |
| 3 | 세종대왕 | sejong@example.com |
| 4 | 이순신 | sunsin@example.com |
| 5 | 마리 퀴리 | marie@example.com |
| 6 | 레오나르도 다빈치 | vinci@example.com |
orders 테이블 조회
SELECT user_id, order_id FROM orders
ORDER BY user_id;
실행 결과
| user_id | order_id |
|---|---|
| 1 | 1 |
| 1 | 2 |
| 2 | 3 |
| 2 | 7 |
| 3 | 4 |
| 4 | 5 |
내부 조인으로 시도해보기
- 결과를 한 번에 쉽게 확인하기 위해 내부 조인(
INNER JOIN)을 사용해서 고객과 주문을 연결해보자.
SELECT
u.user_id,
u.name,
o.user_id,
o.order_id
FROM users u
JOIN orders o ON u.user_id = o.user_id
ORDER BY u.user_id;
INNER는 생략했다.INNER를 생략하고JOIN만 적으면 내부 조인(INNER JOIN)으로 작동한다.- 조인 과정을 보면 레오나르도 다빈치의
users.user_id:6에 해당하는orders.user_id:6이 없다. - 따라서 레오나르도 다빈치는 조인 대상에서 제외된다.
실행 결과
| user_id | name | user_id | order_id |
|---|---|---|---|
| 1 | 션 | 1 | 1 |
| 1 | 션 | 1 | 2 |
| 2 | 네이트 | 2 | 3 |
| 2 | 네이트 | 2 | 7 |
| 3 | 세종대왕 | 3 | 4 |
| 4 | 이순신 | 4 | 5 |
| 5 | 마리 퀴리 | 5 | 6 |
- 결과를 보면 '레오나르도 다빈치'(
user_id: 6)가 결과에서 완전히 사라졌다. - 내부 조인(
INNER JOIN)은 양쪽 테이블에 모두 존재하는 데이터만 보여주기 때문이다. - 즉 주문 기록이 없는 고객은
orders테이블에 짝이 없어서 결과에서 제외된다.
4.2 외부 조인의 필요성
- 외부 조인(
OUTER JOIN)은 두 테이블을 조인할 때, 특정 테이블의 데이터는ON조건이 맞지 않더라도 모두 결과에 포함시키는 방법이다. - 이때 기준이 되는 테이블이 어느 쪽이냐에 따라
LEFT OUTER JOIN과RIGHT OUTER JOIN으로 나뉜다. - 교집합 영역은 물론이고, 기준이 되는 테이블의 데이터는 결과에 모두 포함된다.
- '레오나르도 다빈치'(
user_id: 6)를 결과에 포함하려면LEFT OUTER JOIN을 선택하면 된다.
풀 외부 조인(FULL OUTER JOIN)
- 양쪽 모두를 함께 포함하는 풀 외부 조인이라는 방법도 있다.
- 실무에서 잘 사용하지 않고, MySQL은 지원하지 않는다.
4.3 LEFT JOIN vs RIGHT JOIN
- 외부 조인의 핵심은 '기준 테이블'을 정하는 것이다.
LEFT OUTER JOIN은 왼쪽 테이블을,RIGHT OUTER JOIN은 오른쪽 테이 블을 기준으로 삼는다.
OUTER는 생략 가능
- 다음과 같이 OUTER는 생략해서 사용할 수 있다. 실무에서는 생략하는 것을 권장한다.
LEFT OUTER JOIN→LEFT JOINRIGHT OUTER JOIN→RIGHT JOIN
LEFT JOIN (또는 LEFT OUTER JOIN)
LEFT JOIN구문의 왼쪽(FROM 절)에 있는 테이블이 기준이 된다.- 일단 왼쪽 테이블의 모든 데이터를 결과에 포함시킨다.
- 그다음,
ON조건에 맞는 데이터를 오른쪽 테이블에서 찾아 옆에 붙여준다. - 만약 오른쪽 테이블에 짝이 맞는 데이터가 없다면, 그 자리는
NULL값으로 채워진다.
RIGHT JOIN (또는 RIGHT OUTER JOIN)
RIGHT JOIN구문의 오른쪽(JOIN 절)에 있는 테이블이 기준이 된다.- 일단 오른쪽 테이블의 모든 데이터를 결과에 포함시킨다.
- 그다음,
ON조건에 맞는 데이터를 왼쪽 테이블에서 찾아 붙인다. - 마찬가지로 왼쪽 테이블에 짝이 맞는 데이터가 없다면, 그 자리는
NULL로 채워진다.
4.4 LEFT JOIN으로 '한 번도 주문하지 않은 고객' 찾기
- 첫 번째 질문, "한 번도 주문하지 않은 고객은 누구인가?"에 답을 찾아보자.
- 이 질문의 기준은 '고객'이다. 따라서
users테이블이LEFT JOIN의 왼쪽에 위치해야 한다.
1단계: users를 기준으로 orders 테이블 LEFT JOIN 하기
- 먼저
users테이블의 모든 고객을 일단 다 보여주고, 오른쪽에 주문 정보를 붙여보자.
SELECT
u.user_id,
u.name,
o.user_id,
o.order_id
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id
ORDER BY u.user_id;
LEFT JOIN을 사용했다.users가 왼쪽이고,orders가 오른쪽이다.- SQL을 보면 FROM 다음에
users가 먼저 나오고 그 다음에orders가 나온다.
실행 결과
| user_id | name | user_id | order_id |
|---|---|---|---|
| 1 | 션 | 1 | 1 |
| 1 | 션 | 1 | 2 |
| 2 | 네이트 | 2 | 3 |
| 2 | 네이트 | 2 | 7 |
| 3 | 세종대왕 | 3 | 4 |
| 4 | 이순신 | 4 | 5 |
| 5 | 마리 퀴리 | 5 | 6 |
| 6 | 레오나르도 다빈치 | NULL | NULL |
- 실행 결과를 보자.
INNER JOIN에서는 보이지 않던 '레오나르도 다빈치(user_id:6)'가 드디어 나타났다. - 그는 주문 기록이 없기 때문에,
orders테이블에서 가져온user_id와order_id컬럼의 값이 모두NULL로 채워져 있다. - 이것이 바로
OUTER JOIN이다.
2단계: NULL인 데이터만 필터링하기
- 주문 정보가
NULL인 고객이 바로 '한 번도 주문하지 않은 고객'이다. WHERE절을 사용해서 이들만 찾아보자.
SELECT
u.user_id,
u.name,
u.email
FROM users AS u
LEFT JOIN orders AS o ON u.user_id = o.user_id
WHERE o.order_id IS NULL;
NULL 비교
NULL은 '값이 없음'을 나타내는 특별한 상태이므로,=연산자로 비교할 수 없다.- 반드시
IS NULL또는IS NOT NULL을 사용해야 한다.
4.5 LEFT JOIN vs RIGHT JOIN 실무 사용
- 실무에서는
LEFT JOIN이RIGHT JOIN보다 훨씬 더 많이 사용된다. - 보통 분석의 기준이 되는 테이블을
FROM절에 먼저 쓰고, 필요한 정보를 담은 다른 테이블들을LEFT JOIN으로 하나씩 붙여나가는 방식으로 쿼리를 작성하는 것이 더 직관적이기 때문이다. RIGHT JOIN은 테이블의 순서를 바꾸면 언제나LEFT JOIN으로 동일하게 표현할 수 있다.
정리
LEFT JOIN과RIGHT JOIN은 조인할 때 기준 테이블의 위치를 정한다.- 사람들은 보통 위에서 아래로, 왼쪽에서 오른쪽으로 글을 읽기 때문에 기준이 되는 내용이 먼저 나오는 것을 선호한다.
LEFT JOIN은 기준 테이블이FROM절에 먼저 나오므로 더 읽기 편하다.- 따라서 기준 테이블을
FROM절에 먼저 쓰는 습관을 들이는 것이 좋다. FROM과JOIN절에 있는 테이블의 위치를 바꾸면LEFT JOIN을RIGHT JOIN으로 변경할 수 있다.- 반대로,
FROM과JOIN절에 있는 테이블의 위치를 바꾸면RIGHT JOIN을LEFT JOIN으로 변경할 수 있다. - 이러한 이유로 실무에서는 대부분
LEFT JOIN을 사용하며,RIGHT JOIN은 잘 사용하지 않는다.
5. 조인의 특징
- 두 테이블을 조인할 때 어떤 경우에는 행이 더 늘어나고 어떤 경우에는 행이 늘어나지 않고 그대로인 경우가 있다.
- 이 부분은 데이터베이스를 다루는 데 있어 정말 중요하므로 반드시 제대로 이해해야 한다.
5.1 조인 시 행 수 변화의 원리
- 조인은 다음과 같은 특징이 있다.
- 기준으로 삼는 테이블의 한 행(Row)이 다른 쪽 테이블의 여러 행과 연결될 수 있다면, 결과의 전체 행 수는 늘어난다.
- 반대로 한 행이 다른 쪽 테이블의 단 하나의 행과 연결되거나, 아무 행과도 연결되지 않는다면 행의 수는 늘어나지 않는다.
- 그렇다면 대체 언제 행이 늘어나고, 언제 그대로일까?
- 이 원리를 이해하려면 테이블 간의 관계, 특히 **기본 키(Primary Key, PK)**와 **외래 키(Foreign Key, FK)**의 관계를 알아야 한다.
Primary Key (PK)
- 테이블에서 각 행을 고유하게 식별하는 값이다.
users테이블의user_id나products테이블의product_id가 여기에 해당한다.- PK는 테이블 내에서 절대로 중복될 수 없다.
Foreign Key (FK)
- 다른 테이블의 PK를 참조하는 값이다.
orders테이블의user_id는users테이블의user_id를 참조하는 FK다.- FK는 참조하는 테이블에서 여러 번 중복되어 나타날 수 있다.
- 예를 들어, 한 명의 고객(
user_id)이 여러 번의 주문(orders)을 할 수 있기 때문이다.
5.2 부모-자식 관계
- 이 관계를 '부모-자식 관계'에 비유하면 이해하기 쉽다.
- 부모 테이블 (Parent Table): PK를 가지고 있는 테이블. (
users,products) - 자식 테이블 (Child Table): FK를 통해 부모 테이블을 참조하는 테이블. (
orders)
5.3 조인 시 데이터 행 수 변화 규칙
1. 자식 → 부모 조인 (FK → PK 참조): 행 개수가 늘어나지 않는다
orders테이블을 기준으로users테이블을 조인하는 경우다.- 자식 테이블(
orders)의 각 주문 정보는 반드시 **단 한 명의 부모(users)**하고만 연결된다. - 주문 하나가 여러 고객의 것일 수는 없기 때문이다.
- 따라서 기준 테이블인
orders의 행 개수가 그대로 유지된다. - PK는 유일한 하나의 값만 저장된다. 따라서 PK 방향으로 참조하는 경우 행 개수가 늘어나지 않는다.
2. 부모 → 자식 조인 (PK → FK 참조): 행 개수가 늘어날 수 있다
users테이블을 기준으로orders테이블을 조인하는 경우다.- 부모 테이블(
users)의 한 고객은 **여러 명의 자식(여러 건의orders)**을 가질 수 있다. - 이 경우, 한 고객의 정보를 여러 주문 정보에 각각 매칭시켜야 하므로, 고객 정보 행이 주문 건수만큼 복제되어 전체 행의 수가 늘어난다.
- FK는 같은 값을 여러개 저장할 수 있다. 따라서 FK 방향으로 참조하는 경우 행 개수가 늘어날 수 있다.
5.4 정리: 언제 행이 늘어나고 언제 그대로인가?
- 조인 시 결과 행의 수가 변하는지 여부는 두 테이블의 관계와 어떤 테이블을 기준으로 삼는지에 달려있다.
행 개수 유지: 자식에서 부모로 조인할 때 (to-One)
- FK → PK 조인
- 방향:
FROM 자식 테이블 JOIN 부모 테이블(예:FROM orders JOIN users) - 원리: 자식 테이블의 모든 행은 부모 테이블의 단 하나의 행과 매칭된다. (주문은 반드시 한 명의 고객에게 속한다.)
- 결과: 기준이 되는 자식 테이블의 행 개수가 그대로 유지된다.
orders테이블이 7행이면 결과도 7행이다.
행 개수 증가 가능: 부모에서 자식으로 조인할 때 (to-Many)
- PK → FK 조인
- 방향:
FROM 부모 테이블 JOIN 자식 테이블(예:FROM users JOIN orders) - 원리: 부모 테이블의 한 행은 자식 테이블의 여러 행과 매칭될 수 있다. (한 명의 고객이 여러 번 주문할 수 있다.)
- 결과: 부모 행이 자식 행의 개수만큼 복제되면서 전체 행의 수가 기준 테이블보다 늘어날 수 있다. 주문을 2번 한 고객은 결과 테이블에서 2개의 행을 차지하게 된다.