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

3-8 연습 문제 — 처음 보는 테이블도
다섯 단계로 읽어냅니다

섹션 3의 마지막 연습입니다. 오늘은 새로 배운 게 없으니 지금까지 배운 전부를 씁니다 — 한 행의 주인공, 컬럼의 약속, 데이터 타입, 기본키, 외래키, 그리고 구조를 바꾸고 지우는 명령까지. 종합 진단이라고 생각하고 풀어보세요.

문제4문제 (도전 1 포함)권장 소요20분사용 테이블order_items · 가상 테이블준비물없음 — 3-1 ~ 3-7 복습

섹션 3 에서의 위치

3-6 · 3-7 만들기 · 바꾸기

완료 ✓

3-8 종합 정리

강의 완료 ✓

3-8 연습 문제

지금 여기

섹션 4 DB 모델링

다음 여정

AI 과외 선생님 활용법

2-4에서 만든 AI 과외 선생님 세션을 그대로 쓰세요. 오늘은 특히 이렇게 물어보면 좋습니다 — “내가 이 테이블을 다섯 단계로 이렇게 읽었는데, 빠뜨린 단계나 잘못 읽은 곳이 있어?” 정답을 받아 적는 것보다 본인이 먼저 다섯 칸을 채우고 검증받는 것이 훨씬 남습니다.

문제 1. 처음 보는 테이블을 다섯 단계로 읽으세요

배송을 관리하는 테이블 하나를 새로 받았다고 해봅시다. 이 테이블은 지금까지 한 번도 본 적이 없습니다.

처음 보는 테이블 — deliveries
컬럼타입규칙
delivery_idINTPRIMARY KEY · AUTO_INCREMENT
order_idINTNOT NULL · FOREIGN KEY → orders(order_id)
addressVARCHAR(200)NOT NULL
statusVARCHAR(20)NOT NULL · DEFAULT '준비중'
delivered_atDATENULL 허용
컬럼 목록만 보고 다섯 단계의 답을 채워보세요
가상 예시입니다

deliveries 는 실제 shop 스키마에 없습니다. 처음 보는 테이블을 읽는 훈련을 위해 만든 가상의 테이블이에요.

다섯 칸을 모두 채운 뒤, 아래 두 가지도 함께 답해보세요.

  • 새 배송 행을 저장하면서 status를 생략하면 무엇이 저장될까요?
  • delivered_atNULL인 행은 무슨 뜻일까요?
정답 보기
deliveries 를 다섯 단계로 읽으면
단계
① 테이블 이름deliveries — 배송을 저장하는 테이블
② 한 행의 의미배송 한 건 (주문 한 건에 대한 배송)
③ 컬럼과 규칙주소와 상태는 필수 · 상태의 기본값은 준비중 · 배송완료일은 비워둘 수 있음
④ 기본키delivery_id — 컬럼 하나로 구성
⑤ 외래키order_id → orders.order_id (자식: deliveries, 부모: orders)

② 가 가장 중요합니다. 한 행의 주인공은 배송 한 건이에요. 주문 번호가 들어 있다고 해서 주인공이 주문이 되는 건 아닙니다 — orders의 한 행 안에 회원 번호가 있어도 주인공이 주문이었던 것과 같습니다.

status를 생략하면 → 준비중이 저장됩니다. DEFAULT가 설정된 컬럼은 값을 생략했을 때 미리 정해둔 값이 들어갑니다.

delivered_atNULL이면 → 아직 배송이 완료되지 않았다는 뜻입니다. 배송일이 기록되지 않은 상태 그 자체예요. 이 자리에 0이나 '없음'을 넣으면 기록된 값이 있다는 뜻이 되어버립니다.

⑤ 를 읽었다면 이것도 보입니다. order_idorders에 없는 주문 번호를 넣으면 저장이 거부됩니다. 참조 무결성 — 주소를 적었다면 실제로 존재하는 곳이어야 한다는 약속이죠.

문제 2. 실제 order_items 를 다섯 단계로 읽으세요

이번엔 진짜 우리 shop 테이블입니다. 아래는 order_items의 데이터 일부예요.

shop DB — order_items 앞부분
order_idproduct_idquantity
111
1162
2221
391
3111
64 rows

다섯 단계로 읽은 뒤, 아래 세 질문에 답하세요.

함께 답할 세 가지
#질문
기본키는 무엇인가요? order_id 하나만으로는 왜 안 될까요?
이 테이블의 외래키는 몇 개이고 각각 어디를 가리키나요?
주문 1번에 상품 1번을 두 줄로 넣을 수 있을까요?
힌트

데이터를 세로로 훑어보세요. order_id 열에서 1이 두 번, 3이 두 번 나옵니다. 그렇다면 한 컬럼만으로 각 행을 구별할 수 있을까요?

정답 보기
order_items 를 다섯 단계로 읽으면
단계
① 테이블 이름order_items — 주문에 담긴 상품을 저장하는 테이블
② 한 행의 의미주문에 포함된 상품 한 종류
③ 컬럼과 규칙quantity INT NOT NULL — 그 상품을 몇 개 담았는가
④ 기본키(order_id, product_id) — 두 컬럼이 함께 구성한 하나의 기본키
⑤ 외래키order_id → orders.order_id · product_id → products.product_id

order_id만으로는 안 됩니다. 주문 1번에 상품 1번과 16번이 들어 있어 order_id 값이 중복돼요. product_id만 봐도 같은 상품이 여러 주문에 들어가니 중복입니다. 하지만 두 컬럼을 한 쌍으로 묶으면 (1,1), (1,16), (2,22), (3,9), (3,11) — 겹치는 쌍이 없어 각 행이 구별됩니다.

여기서 자주 나오는 오해 하나 — 기본키가 두 개인 게 아닙니다. 기본키는 하나이고, 그 하나를 두 컬럼이 함께 구성하는 것뿐이에요. 이걸 복합키라고 부릅니다.

② 외래키는 두 개입니다. order_idorders를, product_idproducts를 가리킵니다. 이 테이블은 두 부모를 동시에 가리키는 자식인 셈이에요. 그래서 존재하지 않는 주문 번호나 상품 번호는 저장할 수 없습니다.

③ 넣을 수 없습니다. (1, 1) 쌍이 이미 기본키로 저장돼 있으니 같은 쌍을 한 번 더 저장하면 중복이라 거부됩니다. 같은 상품을 세 개 샀다면 행을 세 번 만드는 대신 quantity3을 저장하는 거예요 — 실제로 (1, 16, 2) 행이 그 예입니다. 상품 16번을 2개 담았다는 뜻이죠.

문제 3. AI 가 만든 구조를 검토하세요

AI에게 “쇼핑몰 쿠폰 테이블을 만들어줘” 라고 요청했더니 아래 구조가 나왔습니다. 실행하기 전에 다섯 항목으로 검토하세요.

AI 가 만들어준 구조 — 테이블 이름 tbl1
컬럼타입규칙 · 값 예시
coupon_nameVARCHAR(50)NOT NULL — 신규가입 3천원 할인
discountVARCHAR(10)NOT NULL — '3000'
member_nameVARCHAR(50)NOT NULL — 김철수
issued_expiresVARCHAR(30)NOT NULL — 2026-05-01~2026-06-01
기본키와 외래키는 하나도 설정되지 않았습니다
가상 예시입니다

이 쿠폰 테이블은 실제 shop 스키마에 없습니다. 검토 훈련을 위해 일부러 잘못 만든 가상의 구조예요. 이대로 만들지 마세요.

다섯 항목(이름 · 한 행의 의미 · 컬럼과 타입 · 필수값과 기본값 · 기본키와 외래키) 중 무엇이 잘못됐는지 찾고, 각각 어떻게 고칠지 적어보세요.

정답 보기
검토 결과 — 다섯 항목 중 네 곳이 문제입니다
항목문제이렇게 고칩니다
① 테이블 이름tbl1 — 무엇을 저장하는지 알 수 없다coupons
② 한 행의 의미쿠폰 종류 하나인지, 발급된 쿠폰 한 장인지 불분명먼저 정한다 — 여기서는 발급된 쿠폰 한 장
③ 컬럼과 타입discount 가 문자열 · 두 날짜가 한 칸에discount INT · issued_at DATE + expires_at DATE
⑤ 기본키와 외래키기본키 없음 · 회원을 이름으로 기록coupon_id PK · member_id FK → members(member_id)

tbl1은 간판이 없는 건물입니다. 다섯 단계의 첫 칸부터 채울 수 없어요. 컬럼 이름이 표지판이라면 테이블 이름은 간판입니다.

② 는 사람이 결정해야 하는 부분입니다. 쿠폰 종류를 담는 테이블인지, 회원에게 발급된 쿠폰 한 장을 담는 테이블인지에 따라 필요한 컬럼이 완전히 달라집니다. AI는 이걸 대신 정해주지 않아요. member_name이 들어 있는 걸 보면 발급된 쿠폰 한 장을 의도한 것 같지만 — 추측이 아니라 결정이 필요합니다.

③ 은 3-2와 3-3 위반이 하나씩 있습니다.

  • discount VARCHAR → 할인 금액은 더하고 비교할 값이라 INT가 맞습니다. 문자열로 두면 정렬할 때 '3000''500'보다 앞에 오는 일이 벌어져요.
  • issued_expires → 발급일과 만료일이 한 칸에 들어 있습니다. 따로 찾고 비교하고 바꿔야 하는 값이라면 각각의 컬럼으로. issued_at DATEexpires_at DATE 두 개로 나눠야 “오늘 기준 만료된 쿠폰” 같은 조건도 쓸 수 있습니다.

⑤ 가 가장 큽니다. 기본키가 없으면 똑같은 행이 두 번 저장돼도 막을 수 없고, 쿠폰 한 장을 정확히 가리킬 수도 없습니다. 그리고 회원을 이름으로 기록하면 — 동명이인을 구별할 수 없고, 이름이 바뀌면 연결이 끊깁니다. member_idmembers를 참조해야 존재하지 않는 회원의 쿠폰이 저장되는 것도 막을 수 있어요.

④ 필수값과 기본값은 그럭저럭입니다. 다만 사용 여부를 담는 컬럼을 둔다면 DEFAULT를 함께 정하는 게 좋겠죠 — 생략했을 때 무엇이 들어갈지 미리 정해두는 겁니다.

여기서 얻어갈 감각

AI는 그럴듯한 구조를 빠르게 만들어줍니다. 하지만 어떤 데이터를 어떤 규칙으로 저장할지는 결국 사람이 결정합니다. 생성은 도구가 — 검토는 사람이.

문제 4 (도전). 섹션 3 종합 — 참일까요, 거짓일까요

섹션 3 전체를 아우르는 진술 여덟 개입니다. 각각 참·거짓을 판정하고 근거 한 줄을 붙이세요. 근거를 쓰지 못하면 아직 그 강의로 돌아갈 때입니다.

참 · 거짓을 판정하세요
#진술
테이블의 한 행은 주인공 하나에 대한 기록이고, 컬럼은 모든 행에 던지는 같은 질문이다
나이를 아직 모르는 회원의 age 에는 0 을 넣어두면 된다
우편번호처럼 숫자로만 이루어진 값은 항상 INT 로 저장하는 게 맞다
order_items 는 기본키가 두 개다
orders.member_id 에 members 에 없는 999 를 넣으면 저장은 되고, 나중에 조회할 때 오류가 난다
우리 shop DB 에서 주문이 있는 김철수(1번) 회원 행을 지우려 하면 MySQL 이 막는다
DELETE 로 order_items 의 모든 행을 지워도 order_items 의 컬럼과 규칙은 그대로 남는다
NULL 을 허용하고 DEFAULT 도 있는 컬럼에 NULL 을 명시해 넣으면 NULL 이 저장된다
여덟 개 중 참은 네 개, 거짓은 네 개입니다
정답 보기
#판정근거강의
행은 주인공 하나에 대한 기록 한 세트, 열은 모든 주인공에게 던지는 같은 질문3-1
거짓모르는 것과 0은 다릅니다 — 기록되지 않은 상태는 NULL3-2
거짓06234INT에 넣으면 앞의 0이 사라집니다 — 계산하지 않는 번호는 문자열3-3
거짓기본키는 하나입니다 — 그 하나를 order_idproduct_id가 함께 구성3-4
거짓외래키가 설정돼 있으면 저장 시점에 막힙니다 — 참조 무결성3-5
삭제 옵션을 따로 설정하지 않아 자식이 있는 부모는 삭제가 차단됩니다3-5
DELETE는 행만 지웁니다 — 테이블 자체를 없애는 건 DROP3-7
DEFAULT는 값을 생략했을 때만 동작합니다3-2

②와 ③은 같은 함정입니다. 겉모양에 속아 그릇을 잘못 고르는 것 — 값이 없는 상태를 0으로 대신하거나, 숫자처럼 보인다고 숫자 타입에 넣는 거죠. 둘 다 오류 없이 저장되고, 나중에 그럴듯하게 틀린 결과로 돌아옵니다.

⑤가 오늘의 핵심 오해입니다. 외래키는 잘못된 값이 들어간 뒤에 알려주는 경고가 아니라 — 저장 자체를 거부하는 규칙입니다. 그래서 *“누구의 주문인지 영원히 알 수 없는 기록”*이 애초에 생기지 않아요.

⑥과 ⑦은 함께 기억하세요. ⑥은 참조 무결성이 삭제에도 작동한다는 뜻이고, ⑦은 삭제 명령마다 사라지는 범위가 다르다는 뜻입니다. DELETE는 행, TRUNCATE는 모든 행, DROP은 테이블 전체 — 실행 뒤 무엇이 남는지부터 생각하는 습관이 오래 갑니다.

⑥ 을 직접 실행해보고 싶다면

실습 DB에서 members 1번을 지워봐도 괜찮습니다 — 오류가 나면서 삭제가 막히므로 데이터는 그대로예요. 다만 자식 행을 먼저 지우는 식으로 더 실험했다면 init.sql을 다시 실행해 원래 상태로 되돌려 두세요.

다 풀었다면

✓ 3-8 훈련 완료 기준

처음 보는 테이블 앞에서 컬럼부터 훑지 않고 — 이름 · 한 행의 의미 · 컬럼과 규칙 · 기본키 · 외래키를 순서대로 묻게 됐다면 섹션 3의 목표는 전부 달성입니다.

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

DBeaver 좌측 트리에서 shop → Tables 를 열고 productscategories 를 차례로 더블클릭해 보세요. Columns 탭에서 ③ 컬럼과 규칙을, Constraints 탭에서 ④ 기본키를, Foreign Keys 탭에서 ⑤ 외래키를 확인할 수 있습니다. 오늘 배운 다섯 칸을 이 두 테이블에 대해서도 채워보세요.

이제 이미 있는 테이블을 읽는 힘은 갖췄습니다. 다음은 반대 방향이에요 — 표가 하나도 없는 상태에서 업무 이야기만 듣고, 어떤 테이블을 몇 개 만들고 어떻게 연결할지 정하는 데이터베이스 모델링입니다.

NEXT LESSON4-1 관계의 구조 — 사고법 전환

이제 방향을 반대로 — 업무 문장을 읽고 어떤 테이블이 필요한지 직접 정하는 모델링을 시작합니다.

GO ▸ 섹션 4 시작하기