강의에서 가장 중요한 한 강,
부모 테이블 vs 자식 테이블
부모는 PK를 가진 기준 데이터, 자식은 FK로 부모를 가리키는 데이터 — 정의는 이게 전부입니다. 그런데 이 한 개념으로 DB 모델링의 80%, SQL의 80%가 풀립니다. 이 한 강만 제대로 잡아도 "강의 값어치 했다"고 솔직히 말씀드릴 수 있어요. 천천히 같이 갑니다.
이번 섹션의 여정
완료 ✓
지금 여기
관계 유형 · FK · ERD
정규화 · 실무 ERD · 종합 실습 ⭐
AI에게 구조를 주는 법
부모 = PK, 자식 = FK — 정의는 두 줄이면 끝
4-1에서 “데이터베이스는 테이블이 아니라 관계의 구조” 라고 사고법을 바꿨죠. 오늘은 그 관계를 읽는 단 하나의 도구를 손에 쥡니다. 단순합니다.
부모 테이블 = PK(기본키)를 가진, 기준이 되는 테이블.
자식 테이블 = FK(외래키)로 부모를 가리키는 테이블.
쇼핑몰로 예를 들면 — 회원(members)이 부모, 주문(orders)이 자식입니다. 왜냐? 주문에는 “누가 주문했냐” 가 member_id로 박혀 있어요. 주문이 회원 테이블을 가리키고 있는 겁니다. 3-6에서 본 그 그림 — 이제 정식 이름을 붙입니다.
진짜 그런지 데이터로 확인해 볼까요. orders의 아무 행이나 꺼내 보면 —
| order_id | member_id | ordered_at |
|---|---|---|
| 1 | 1 | 2025-02-01 |
| 2 | 2 | 2025-02-15 |
| 3 | 3 | 2025-03-01 |
회원이 가입해야 → 주문이 생깁니다. 부모가 먼저, 자식이 나중 — 시간적으로도, 데이터적으로도. 어느 쪽이 부모인지 헷갈리면 “어느 쪽이 먼저 존재해야 하는가” 를 물어보세요.
그런데 PK(기본키)가 정확히 뭔가요?
앞에서 부모 = PK 를 가진 테이블 이라고 했죠. members → orders 한 쌍을 봤으니, 5테이블 전체로 넓히기 전에 — 다이어그램에 붙어 있던 그 PK 부터 1분만 정확히 짚고 갈게요. 부모를 부모답게 만들어주는 게 바로 이 PK 거든요.
기본키(Primary Key) = 한 테이블에서 각 행을 유일하게 식별하는 컬럼.
members 의 member_id 1번은 이 세상에 김철수 한 명뿐 — PK 하나만 던지면
“어느 행이냐” 가 단 하나로 콕 집힙니다. 이름·나이는 겹쳐도 PK 는 절대
안 겹쳐요.
그래서 PK 에는 세 가지 약속이 따라붙습니다.
| PK 의 세 가지 약속 | 뜻 |
|---|---|
| 중복 불가 | 같은 값이 두 행에 올 수 없다 — member_id 1번은 딱 하나 |
| NULL 불가 | 비어 있으면 식별이 안 되니 금지 — 부모는 반드시 이름표를 단다 |
| 테이블당 하나 | 단, 여러 컬럼을 묶은 복합키도 PK 하나로 친다 (4-3에서 등장) |
shop 의 5테이블에도 각자 PK 가 하나씩 박혀 있어요.
AUTO_INCREMENT 덕분에 회원가입할 때 member_id 를 직접 정할 필요가 없습니다. DB 가 “넌 21번” 하고 다음 번호를 알아서 붙여주거든요 — 그래서 실무 PK 는 거의 다 이 형태예요.
PK 가 중요한 진짜 이유 — 가리킴의 대상이 되기 때문입니다.
자식(orders)이 부모(members)를 가리킬 때, 정확히 부모의 PK(member_id)
를 가리켜요. 앞 다이어그램에서 본 그 화살표 — 그게 바로 4-4 에서 본격적으로
배울 FK(외래키) 입니다. PK 없는 테이블은 누구도 가리킬 수 없어요.
shop 5테이블 — 부모-자식 4쌍으로 전부 분해됩니다
이제 shop의 5테이블 전체를 부모 / 자식으로 분류해 볼게요.
| 부모 | 자식 | 어떤 관계 |
|---|---|---|
members (회원) | orders (주문) | 1명이 여러 주문 |
orders (주문) | order_items (주문상세) | 1주문에 여러 상품 |
products (상품) | order_items (주문상세) | 1상품이 여러 주문에 |
categories (카테고리) | products (상품) | 1카테고리에 여러 상품 |
보세요 — 테이블 5개가 부모-자식 4쌍으로 깔끔하게 분해됩니다. 아무리 복잡한 ERD도 똑같아요. 테이블이 50개든 500개든, 결국 부모-자식 쌍의 모음일 뿐입니다.
그리고 표를 자세히 보면 한 가지가 눈에 들어옵니다 — orders가 두 번 나오죠. 한 번은 자식 칸에, 한 번은 부모 칸에.
orders는 members에게는 자식이고, order_items에게는 부모입니다. 부모 / 자식은 테이블의 고정 신분이 아니에요. 한 테이블의 성격을 따로 정하지 말고, 항상 “누구와의 관계인가” 로 보세요.
강의의 한 줄 — 모든 SQL은 부모-자식 위에 있다
자, 여기서 — 이 강의가 약속한 그 문장이 본격적으로 등장합니다.
과장이 아닙니다. 강사가 20년 동안 SQL을 짜면서 머리에 떠올린 건 항상 부모-자식이었어요. “이 데이터 어떻게 뽑지?” 라는 질문은 결국 — “어디서 시작해서, 자식 → 자식 → 자식을 따라가면 도착할까?” — 이게 SQL의 사고 흐름입니다. 섹션 3에서 배운 문법들을 부모-자식 안경을 쓰고 다시 보면:
| SQL 패턴 | 부모-자식 관점 |
|---|---|
JOIN ... ON ... | 부모ID = 자식ID — 3-6의 90% 법칙 |
GROUP BY | 부모 단위로 묶는다 |
WHERE ... IN (...) | 이 부모들에 해당하는 자식만 |
LEFT JOIN + IS NULL | 자식 없는 부모 찾기 |
| JOIN 뻥튀기 | 자식이 N개라 부모가 N번 곱해짐 — 3-7의 함정 |
모든 SQL 패턴이 부모-자식 위에 얹혀 있습니다. 새 패턴이 아니라 — 이미 배운 것들의 공통 뿌리를 오늘 찾은 거예요.
AI에게는 부모-자식부터 알려주세요
그래서 AI에게 SQL을 시킬 때 — 부모-자식 정보를 주면 정확도가 확 올라갑니다. 같은 요구사항을 두 가지 방식으로 던져 보면 차이가 바로 보여요.
”shop DB에서 회원별 매출 뽑아줘”
AI가 어떤 테이블을 어떻게 연결할지 추측합니다. 그럴듯한 SQL이 나오지만 — 맞는지 따지는 검증에 시간이 더 들어요. 추측 위에 쌓은 답이니까요.
부모-자식 관계를 명시
테이블·PK·FK·가리키는 방향까지 주면 AI가 거의 안 틀립니다. 검증도 1초 — JOIN의 ON 조건이 내가 준 관계와 일치하는지만 보면 되거든요.
좋은 프롬프트는 이렇게 생겼습니다. 그대로 복사해서 AI 과외 선생님(2-4)에게 던져 보세요.
shop DB.
[부모-자식 관계]
- members (회원, PK=member_id)
← orders (주문, FK=member_id)
← order_items (주문상세, FK=order_id)
→ products (상품, PK=product_id)
[요구사항]
회원별 총 매출(price × quantity 합)을 매출 많은 순으로.두 프롬프트의 차이는 — 부모-자식 관계를 명시했냐 안 했냐 하나입니다. 이게 “AI 시대의 진짜 SQL 실력” 이에요. 관계를 전달하는 표준 포맷은 섹션 5에서 본격적으로 다듬습니다.
검증 — 부모-자식 체인을 SQL로 따라가기
말로만 하면 심심하니, 방금 배운 부모-자식 사고로 SQL을 직접 짜서 확인해 볼게요. 목표는 위 프롬프트와 같습니다 — 회원별 총 매출, 매출 많은 순. 체인은 members → orders → order_items ← products.
-- 부모-자식 체인 따라가기: 회원별 총 매출
SELECT
m.member_name,
SUM(p.price * oi.quantity) AS 총매출
FROM
members m -- 출발: 부모
JOIN orders o
ON m.member_id = o.member_id -- 자식으로 한 칸 (members의 자식)
JOIN order_items oi
ON o.order_id = oi.order_id -- 자식으로 한 칸 더 (orders의 자식)
JOIN products p
ON oi.product_id = p.product_id -- 가격은 부모(products)에서
GROUP BY
m.member_id,
m.member_name
ORDER BY
총매출 DESC;| member_name | 총매출 |
|---|---|
| 조성민 | 600000 |
| 김철수 | 498000 |
| 박민수 | 356000 |
| 오지은 | 288000 |
| ⋮ | |
복잡해 보이는 쿼리지만 — JOIN 한 줄 한 줄이 부모-자식 한 쌍씩 따라가는 것일 뿐입니다. GROUP BY는 부모(회원) 단위로 묶는 것, SUM은 그 부모에 매달린 자식들의 합. 전부 오늘 배운 안경으로 읽힙니다.
주문(자식)이 없는 회원 4명이 INNER JOIN에서 빠진 겁니다 — 3-6에서 배운 자식 없는 부모 패턴 그대로죠. 행 수가 예상과 다를 때 “부모를 잘못 골랐나? 자식이 N개라 행이 늘었나?” — 이렇게 부모-자식 관점으로 진단하면 3-7의 JOIN 뻥튀기 함정도 1초면 잡힙니다.
곁가지 — 마스터 vs 트랜잭션은 5초만
실무에서 가끔 듣는 말이 있어요 — “마스터 테이블 / 트랜잭션 테이블”. 비즈니스 관점의 분류입니다.
| 의미 | shop에서는 | |
|---|---|---|
| 마스터 | 기준 데이터 — 자주 안 바뀜 | members, categories, products |
| 트랜잭션 | 거래 데이터 — 매일 늘어남 | orders, order_items |
이건 5초만 알면 되는 부가 분류입니다. 모든 모델링의 출발점은 부모-자식 — 이 표는 잊어버려도 괜찮으니, 부모-자식만 기억하세요.
자주 헷갈리는 지점
단골 질문입니다. 답은 — 둘 다. members와의 관계에서는 자식이고,
order_items와의 관계에서는 부모입니다.
PK를 가졌다고 자동으로 부모가 되는 게 아닙니다. 누군가 그 PK를 FK로 가리켜 줄 때 비로소 그 관계의 부모가 돼요.
회원이 없는데 주문부터 넣으려는 상황이죠. shop DB는 FK 제약이 걸려 있어서 —
존재하지 않는 member_id로 주문을 INSERT하면 에러가 납니다.
부모는 PK, 자식은 FK. 모든 모델링과 SQL은 부모-자식 위에 얹혀 있다. 이거 하나만 머리에 박혀 있어도 — 강의의 80%는 이미 잡힌 겁니다.
다음 강의에서는 이 부모-자식 관계 안에서 1:1 / 1:N / N:M을 식별하는 법을 배웁니다. 그 전에 — 연습 문제로 오늘의 안경을 직접 써보세요. 직접 분해해 본 사람과 눈으로만 본 사람의 차이는 생각보다 큽니다.