바이브 코딩 시대의 데이터베이스3-5 연습 문제
테크타니 LEARN — 섹션 03 · 연습 문제

3-5 연습 문제 — 값을 따라가
연결된 행을 찾습니다

이번 강의에서 배운 것 — 자식의 FK → 부모의 PK, 그리고 참조 무결성. 오늘은 주문에서 회원 이름까지 직접 따라가 보고, 어떤 저장과 삭제가 데이터베이스에게 거부되는지 판정해 봅니다.

문제4문제 (도전 1 포함)권장 소요15분사용 테이블shop DB 5개 테이블준비물없음 — 표만 읽으면 OK

섹션 3 에서의 위치

3-4 기본키(PK)

완료 ✓

3-5 외래키(FK)

강의 완료 ✓

3-5 연습 문제

지금 여기

3-6 CREATE TABLE

테이블 직접 만들기

AI 과외 선생님 활용법

2-4에서 만든 AI 과외 선생님 세션을 그대로 쓰세요. 막힐 때 답부터 묻지 말고 — “이 삭제가 왜 막히는지 판단하려면 무엇부터 확인해야 해?” 처럼 판단 순서를 물어보세요. 다 푼 뒤에는 본인이 적은 근거를 붙여서 검증받는 게 가장 남습니다.

문제 1. 이 주문은 누구의 주문일까요

아래는 shop DB 의 실제 데이터 일부입니다. 세 표를 오가며 값을 따라가 보세요.

members (발췌)
member_id (PK)member_name
1김철수
2이영희
3박민수
10한예원
15권현석
16노수아
orders (발췌 — 이영희 회원의 주문은 이 안에 모두 들어 있습니다)
order_id (PK)member_id (FK)ordered_at
222025-02-15
332025-03-01
822025-05-05
13102025-07-15
1822025-09-15
24152025-11-15
3322026-02-05
categories · products (발췌)
product_id (PK)product_namecategory_id (FK)
1라운드 티셔츠1
9무선 이어폰2
16프리미엄 그래놀라3
categories — 1=의류, 2=전자기기, 3=식품, 4=도서, 5=뷰티

네 가지를 각각 찾아보세요. 어떤 값을 들고 어느 표로 갔는지까지 함께 적으면 좋습니다.

따라가 볼 것
#찾아야 할 것
order_id 3 번 주문은 어느 회원의 주문인가
order_id 13 번 주문은 어느 회원의 주문인가
이영희 회원이 한 주문의 order_id 를 모두 고르면
product_id 9 (무선 이어폰) 은 어느 카테고리 상품인가
정답 보기
#따라간 경로
박민수주문 3 → member_id 3 → members 3번 → 박민수
한예원주문 13 → member_id 10 → members 10번 → 한예원
2 · 8 · 18 · 33 (4건)이영희 = member_id 2 → orders 에서 member_id 가 2인 행
전자기기상품 9 → category_id 2 → categories 2번 → 전자기기

①·②·④는 자식에서 부모로 가는 방향입니다. 자식 행의 외래키 값을 들고 부모 테이블의 기본키를 찾아가면 됩니다 — 답은 언제나 한 행이에요. 부모의 기본키는 중복이 없으니까요.

③은 방향이 반대라서 조금 다릅니다. 부모(이영희)에서 출발해 그 번호를 가리키고 있는 자식 행들을 모으는 겁니다. 이쪽은 답이 여러 행일 수 있어요 — 한 부모를 여러 자식이 가리킬 수 있으니까요.

문제 2. 부모와 자식, 화살표는 어느 쪽으로

shop DB 에는 외래키 관계가 네 쌍 있습니다. 각 쌍에서 어느 쪽이 부모이고 어느 쪽이 자식인지 고른 뒤, 화살표를 자식.컬럼 → 부모.컬럼 형태로 적어보세요.

네 쌍의 관계
#두 테이블
members 와 orders
categories 와 products
orders 와 order_items
products 와 order_items
힌트

판단 기준은 하나입니다 — 기본키를 가지고 가리킴을 받는 쪽이 부모, 그 값을 자기 컬럼에 적어둔 쪽이 자식. “어느 테이블이 더 중요한가”로 고르면 틀립니다.

정답 보기
#부모자식화살표 (자식 FK → 부모 PK)
membersordersorders.member_idmembers.member_id
categoriesproductsproducts.category_idcategories.category_id
ordersorder_itemsorder_items.order_idorders.order_id
productsorder_itemsorder_items.product_idproducts.product_id

여기서 얻어갈 게 두 가지 있습니다.

첫째, order_items자식 역할을 두 번 합니다. 부모가 ordersproducts 둘이에요. 한 테이블이 외래키를 여러 개 가질 수 있습니다.

둘째, ordersmembers자식이면서 동시에 order_items부모입니다. 부모·자식은 테이블에 영구히 붙은 신분이 아니라 — 관계 하나하나마다 정해지는 역할이에요.

화살표를 그릴 때

방향은 언제나 자식의 FK 에서 부모의 PK 로. 관계가 몇 개든, 표가 몇 개든 이 방향은 바뀌지 않습니다.

문제 3. 이 시도는 성공할까요, 차단될까요

우리 shop DB 에 아래 다섯 가지를 시도합니다. 각각 성공하는지 차단되는지 판정하고 이유를 적으세요.

다섯 번의 시도
#시도
orders 에 member_id = 999 인 새 주문을 저장
members 에서 20번 백서윤 회원을 삭제
members 에서 1번 김철수 회원을 삭제
products 에 category_id = 9 인 새 상품을 저장
orders 에 member_id 를 비운 채(NULL) 새 주문을 저장
판정에 필요한 사실

members 는 120번, categories 는 15번뿐입니다. 백서윤(20번)을 가리키는 주문은 없고, 김철수(1번)를 가리키는 주문은 6건(1 · 6 · 14 · 20 · 27 · 34) 있습니다. 그리고 orders.member_idNOT NULL 입니다.

정답 보기
#결과이유
차단members 에 999번이 없습니다 — 없는 부모는 가리킬 수 없어요
성공백서윤을 가리키는 자식 행이 하나도 없습니다
차단주문 6건이 이 회원을 가리키고 있습니다
차단categories 는 1~5번뿐입니다 — 9번 카테고리가 없어요
차단orders.member_idNOT NULL 이라서 — 외래키 때문이 아닙니다

①과 ④는 같은 규칙입니다. 테이블만 다를 뿐, 둘 다 존재하지 않는 부모를 가리키려 한 시도예요. 여기서 꼭 짚을 것 — 잘못된 값이 저장된 뒤에 문제가 되는 게 아니라, 저장 자체가 거부됩니다. 참조 무결성은 사후 점검이 아니라 사전 차단이에요.

②와 ③의 차이가 삭제 규칙의 전부입니다. 가리키는 자식이 있으면 부모를 지울 수 없고, 없으면 지울 수 있습니다. 백서윤이 삭제 가능한 이유는 특별해서가 아니라 그저 자식이 없어서예요.

⑤가 오늘의 함정입니다. 차단되는 건 맞지만 이유가 다릅니다. 외래키가 NULL 을 금지하는 게 아니라, 우리가 이 컬럼을 NOT NULL 로 정했기 때문이에요. 만약 NULL 을 허용하도록 설계된 외래키 컬럼이라면 “아직 연결된 부모가 없다” 는 뜻으로 비워둘 수 있습니다.

참고

NULL 을 허용하는 외래키는 개념 설명을 위한 가상의 설계입니다. 실제 shop DB 의 orders.member_idproducts.category_id 는 둘 다 NOT NULL 이에요.

문제 4 (도전). 이 말들은 맞을까요, 틀릴까요

외래키를 처음 배우면 자주 나오는 말들입니다. 각각 참인지 거짓인지 판정하고, 거짓이라면 어디가 틀렸는지 한 줄로 고쳐 쓰세요.

참 / 거짓을 판정하세요
#진술
members 와 orders 에 member_id 라는 같은 이름의 컬럼이 있으니, 따로 규칙을 적지 않아도 두 테이블은 연결된다
외래키 컬럼에는 NULL 을 넣을 수 없다 — 외래키가 곧 NOT NULL 이다
member_id 가 999 인 주문은 일단 저장되고, 나중에 조회할 때 회원을 못 찾아 문제가 된다
회원 행이 있으려면 그 회원의 주문이 최소 한 건은 있어야 한다
orders 는 members 의 자식이면서 동시에 order_items 의 부모다
shop DB 의 외래키는 모두 부모 테이블의 기본키를 가리킨다
여섯 개 중 참인 진술도 섞여 있습니다
정답 보기
#판정근거
거짓이름이 같은 건 사람이 읽기 쉬우라는 관례일 뿐입니다
거짓빈값 규칙은 외래키와 별개로 정하는 약속입니다
거짓저장된 뒤 문제가 되는 게 아니라 저장 자체가 거부됩니다
거짓부모는 자식 없이도 존재할 수 있습니다 — 20번 백서윤
부모·자식은 관계마다 정해지는 역할입니다
우리 샘플 DB 의 외래키 네 개는 전부 부모의 PK 를 가리킵니다

① — 연결을 만드는 건 이름이 아니라 규칙입니다.

설계도에 이 한 줄이 실제로 있어야 합니다.

CONSTRAINT fk_orders_member
  FOREIGN KEY (member_id) REFERENCES members(member_id)

이 규칙이 없으면 데이터베이스가 아는 건 “두 컬럼의 이름이 같다” 는 사실뿐이라, 999를 넣어도 막아주지 않습니다. 그리고 반대도 성립해요 — 컬럼 이름이 서로 달라도 FOREIGN KEY 규칙으로 연결할 수 있습니다.

② — 외래키와 NOT NULL 은 별개의 약속입니다.

외래키가 NULL 을 허용하도록 설계됐다면 “아직 연결된 부모가 없다” 는 뜻으로 비워둘 수 있습니다. 우리 orders.member_id 를 비울 수 없는 건 그 컬럼에 NOT NULL 을 따로 걸어두었기 때문이에요.

③ — 순서를 정확히 기억하세요.

데이터베이스는 저장하기 전에 부모 테이블을 확인합니다. 999번 회원이 없으면 그 자리에서 오류를 내고 거부해요. “잘못된 데이터가 들어간 뒤 나중에 깨진다” 가 아니라 “애초에 들어가지 못한다” 입니다.

④ — 가입만 하고 주문하지 않은 회원은 정상입니다.

20번 백서윤 회원은 members 에는 있지만 주문이 없습니다. 오류도, 누락도 아니에요. 자식이 부모 없이 존재할 수 없을 뿐, 부모는 자식 없이 얼마든지 존재할 수 있습니다.

⑤ — 한 테이블이 두 역할을 겸합니다.

orders.member_id 로 보면 orders 는 자식이고, order_items.order_id 로 보면 orders 는 부모입니다. 그래서 주문 1번을 지우려 하면 order_items 때문에 차단돼요.

⑥ — 다만 문법적으로는 다른 선택지도 있습니다.

외래키가 UNIQUE 처럼 중복을 허용하지 않는 다른 키를 참조할 수도 있습니다. 우리 샘플 DB 가 전부 기본키를 가리키고 있을 뿐이에요. 입문 단계에서는 이 구조부터 확실히 익히면 충분합니다.

여기서 얻어갈 감각

외래키는 “값이 같아 보이는 것”이 아니라 “연결이 보장되는 것”입니다. 그 보장을 만드는 건 컬럼 이름이 아니라 — 설계도에 적힌 FOREIGN KEY 규칙 이에요.

다 풀었다면

✓ 3-5 훈련 완료 기준

표 두 개를 보고 어느 쪽이 부모인지 바로 말할 수 있고, 어떤 저장·삭제가 왜 차단되는지 근거를 대며 설명할 수 있다면 오늘 목표는 달성입니다.

여유가 있다면 — DBeaver 로 직접 확인

DBeaver 좌측 트리에서 shop → Tables → orders 를 더블클릭한 뒤 Foreign Keys 탭을 열어보세요. fk_orders_member 가 어느 테이블의 어느 컬럼을 가리키는지 그대로 보입니다. 이어서 shop 을 더블클릭 → ER Diagram 탭을 열면 다섯 테이블의 화살표가 한눈에 보여요 — 모든 화살표가 자식에서 부모로 향하는지 확인해 보세요.

여기까지 오면 테이블을 만드는 재료를 전부 읽을 수 있게 됐습니다. 컬럼과 타입, 기본키, 그리고 외래키까지. 다음은 이 재료를 SQL 로 직접 적어서 새 테이블을 만들 차례입니다.

NEXT LESSON3-6 테이블 직접 만들기 — CREATE TABLE

지금까지 읽기만 한 스키마를 이번엔 직접 적습니다 — 컬럼 · 타입 · NOT NULL · PK · FK 를 한 문장으로.

GO ▸ 3-6 시작하기