What I Do

기본 키와 외래 키: 표와 표는 어떻게 이어질까

7분 읽기

기본 키는 테이블의 행 하나를 콕 집어 가리키는 열이고, 외래 키는 다른 테이블의 기본 키를 가리켜 두 표를 잇는 열입니다. 1:1·1:N·N:M 관계와 연결 표까지 회원·주문 예시로 알아봅니다.

기본 키와 외래 키: 표와 표는 어떻게 이어질까

기본 키는 테이블에서 행 하나를 콕 집어 가리키는 열이고, 외래 키는 다른 테이블의 기본 키 값을 담아 두 표를 잇는 열입니다. 이 두 열 덕분에 회원 표와 주문 표를 따로 두고도 「이 주문은 누구 것인지」를 언제든 찾을 수 있죠. 저도 SQL 을 처음 배우면서 기본 키 외래 키라는 말이 가장 낯설었는데요, 이번 글에서는 두 키가 무엇이고 표와 표가 어떤 관계로 이어지는지 작은 문구점 예시로 함께 알아보겠습니다. 지난 글: 관계형 데이터베이스 구조: 테이블·행·열·스키마

SQL 기초 시리즈 2/12 · 전체 커리큘럼

오늘 배울 개념

엑셀에서 VLOOKUP 을 써 보셨다면 이미 키를 써 보신 셈인데요, 주문 시트의 「회원번호」로 회원 시트에서 이름을 찾아올 때 회원번호가 바로 키 역할을 하기 때문입니다. 비유하면 기본 키는 주민등록번호처럼 사람마다 하나뿐인 번호이고, 외래 키는 택배 송장에 적힌 그 번호입니다. 송장만 보고도 받는 사람을 찾을 수 있지만, 없는 번호를 적은 송장은 갈 곳이 없죠.

구분기본 키(PK, Primary Key)외래 키(FK, Foreign Key)
하는 일내 테이블의 행을 하나씩 구별다른 테이블의 행을 가리킴
값의 조건겹치면 안 되고 비어 있으면 안 됨가리키는 테이블에 있는 값이거나 NULL
한 테이블에최대 하나여러 개 가능
엑셀로 치면회원 시트의 회원번호 열주문 시트에 적은 회원번호 열

PostgreSQL 제약 조건 문서에 따르면 기본 키는 값이 겹치지 않으면서(unique) 비어 있지도 않아야(not null) 하고, 한 테이블에 최대 하나만 둘 수 있습니다. 같은 문서는 외래 키를 「한 열의 값이 다른 테이블 어떤 행의 값과 일치해야 한다」는 제약으로 설명하고, 이것으로 두 테이블 사이의 참조 무결성(가리키는 값이 실제로 있는 상태)을 지킨다고 적고 있습니다.

예시로 이해하기

지난 글의 문구점에 주문 테이블을 붙여 보겠습니다(가상 데이터).

members (회원)

member_id (PK)namecity
1김하늘서울
2이도윤부산
3박서연서울
4최지우대전

orders (주문)

order_id (PK)member_id (FK)ordered_on
10112026-10-01
10222026-10-03
10312026-10-07
10432026-10-12
10512026-10-20

orders 에는 회원 이름이 없고 member_id 만 있는데요, 주문 105의 주인이 궁금하면 member_id 1을 들고 members 에서 1번 행을 찾으면 김하늘 님이 나옵니다. 이름이 바뀌어도 members 한 곳만 고치면 되죠. PostgreSQL 문서는 이때 orders 처럼 가리키는 쪽을 참조하는 테이블, members 처럼 가리켜지는 쪽을 참조되는 테이블이라고 부르고, SQLite 문서는 각각 자식 테이블·부모 테이블이라고 부릅니다.

members 의 기본 키 member_id 와 orders 의 외래 키 member_id 가 화살표로 이어진 그림 개념 그림: 주문 표의 외래 키가 회원 표의 기본 키를 가리킵니다

스키마로 적으면 이렇습니다. 문법은 6회부터 다루니 PRIMARY KEY 와 REFERENCES 두 단어만 눈여겨보시면 됩니다.

CREATE TABLE members (
    member_id  INTEGER PRIMARY KEY,
    name       VARCHAR(50),
    city       VARCHAR(20)
);
 
CREATE TABLE orders (
    order_id    INTEGER PRIMARY KEY,
    member_id   INTEGER REFERENCES members (member_id),
    ordered_on  DATE
);

이렇게 만들어 두면 members 에 없는 9번 회원의 주문을 넣으려 할 때 PostgreSQL 이 외래 키 위반 오류를 내고 받아들이지 않습니다. 이미 있는 2번으로 회원을 하나 더 넣으려 해도 기본 키 위반으로 막히죠.

표와 표는 어떤 관계로 이어질까요?

MySQL 용어집은 데이터베이스가 일대일·일대다·다대일 같은 관계를 표현하고 지킨다고 설명하는데요, 처음 배울 때는 세 가지로 나눠 보면 충분합니다.

관계뜻예시키를 두는 법
1:1 (일대일)한 행이 상대 표의 행 하나와만 이어짐회원 – 회원 상세 정보외래 키 열이 그 표의 기본 키도 겸함
1:N (일대다)한 행이 상대 표의 여러 행과 이어짐회원 – 주문「다」 쪽(주문)에 외래 키
N:M (다대다)양쪽 모두 여러 행과 이어짐주문 – 상품연결 표를 따로 만듦

위 예시는 1:N 입니다. 김하늘 님은 주문이 셋, 이도윤·박서연 님은 하나씩, 최지우 님은 아직 없죠. 외래 키를 「다」 쪽에 두는 이유는, 지난 글에서 본 것처럼 열 개수가 고정돼 있어 회원 표에 주문 번호 칸을 몇 개 만들어 둘지 정할 수 없기 때문입니다.

그렇다면 주문 하나에 상품이 여러 개 담기고, 상품 하나도 여러 주문에 들어간다면 어떻게 할까요? PostgreSQL 문서는 이런 다대다 관계를 외래 키 두 개를 가진 표로 만드는 예시를 보여 줍니다.

order_items (주문 상품, 연결 표)

order_id (FK)product_id (FK)quantity
10112
10121
10233
10311
10422
10531

product_id 는 볼펜(1)·노트(2)·형광펜(3)이 담긴 products 표를 가리킵니다. 주문 101에는 상품이 둘이고, 볼펜은 주문 101과 103에 들어 있죠. 이 표는 두 열을 묶어 PRIMARY KEY (order_id, product_id) 로 기본 키를 삼는데요, 열 하나로는 겹치지만 둘을 묶으면 같은 조합이 두 번 나오지 않기 때문입니다. SQLite 문서는 이렇게 여러 열로 된 키를 복합 키(composite key)라고 부릅니다.

회원·주문·주문 상품·상품 네 표가 1:N 과 N:M 관계로 이어진 그림 개념 그림: 주문과 상품의 다대다 관계는 주문 상품 표가 가운데서 잇습니다

기본 키는 무엇으로 고를까요?

MySQL 용어집은 기본 키 값을 고를 때 다른 데서 가져온 의미 있는 값(자연 키)보다 아무 의미 없는 일련번호(인조 키)를 고려하라고 권하고, 자연 키는 값이 바뀌면 손볼 곳이 많아진다고 설명합니다.

후보예시장점주의할 점
인조 키1, 2, 3… 회원번호바뀔 일이 없음번호만 봐서는 누구인지 모름
자연 키이메일, 휴대폰 번호따로 번호를 만들 필요 없음사람이 바꿀 수 있고, 바뀌면 손볼 곳이 많음
복합 키(주문번호, 상품번호)연결 표에 잘 맞음가리키는 쪽도 열 두 개를 들고 있어야 함

엑셀 시트를 표로 옮긴다면 저는 이 기준으로 기본 키를 골라 보려고 합니다.

  1. 이 열 값만으로 행이 하나로 정해지는가? 「이름」은 동명이인이 있으니 안 됩니다.
  2. 비어 있는 행이 없는가? 기본 키는 NULL 을 받지 않습니다.
  3. 값이 바뀔 일이 없는가? 바뀔 수 있다면 일련번호를 따로 두고, 이메일은 겹치지 않게만 UNIQUE 를 겁니다.

PostgreSQL 문서는 관계형 이론상 모든 테이블에 기본 키가 있어야 하지만 PostgreSQL 이 이를 강제하지는 않으며, 그래도 따르는 편이 대개 좋다고 적고 있습니다.

연습 문제

1. (쉬움) 위 orders 표에서 기본 키와 외래 키는 각각 어느 열인가요? 외래 키는 어느 표를 가리키나요?

정답 보기

기본 키는 order_id, 외래 키는 member_id 입니다. 외래 키 member_id 는 members 표의 기본 키 member_id 를 가리킵니다. 두 열의 이름이 같을 필요는 없지만 같게 지으면 읽기 쉽죠.

2. (보통) 다음 중 orders 에 넣으려 할 때 막히는 행을 모두 고르세요. (가) (106, 4, 2026-10-25) (나) (107, 9, 2026-10-26) (다) (103, 2, 2026-10-27)

정답 보기

(나)와 (다)입니다. (나)는 members 에 9번 회원이 없어 외래 키에 걸리고, (다)는 주문번호 103이 이미 있어 기본 키에 걸립니다. (가)는 4번 최지우 님의 첫 주문이라 들어갑니다.

3. (보통) 강의 사이트에 「수강생」 표와 「강의」 표가 있습니다. 수강생 한 명이 여러 강의를 듣고, 강의 하나를 여러 수강생이 듣는다면 어떤 관계이고, 표를 어떻게 설계할까요?

정답 보기

다대다(N:M) 관계입니다. 「수강 신청」 같은 연결 표를 만들고 수강생 번호와 강의 번호를 외래 키로 둡니다. 같은 사람이 같은 강의를 두 번 신청하지 못하게 하려면 두 열을 묶어 기본 키로 삼으면 됩니다.

헷갈리기 쉬운 것

  • 외래 키 열에 NULL 은 들어갈 수 있습니다: PostgreSQL 문서에 따르면 외래 키 열이 NULL 이면 일치하는 행이 없어도 제약에 걸리지 않습니다. 「회원 없는 주문」을 막고 싶다면 외래 키 열에 NOT NULL 을 함께 걸어야 합니다.
  • 가리켜지는 행을 지우면 기본으로는 막힙니다: 주문이 남아 있는 2번 회원을 지우려 하면 오류가 나는데요, 외래 키를 만들 때 ON DELETE CASCADE(주문도 함께 삭제)나 SET NULL(외래 키를 NULL 로) 같은 동작을 고를 수 있습니다. PostgreSQL 문서는 두 표가 서로 독립된 대상이면 막아 두는 쪽이 더 알맞다고 설명하는데요, 회원과 주문도 그런 경우로 볼 수 있습니다.
  • 제품마다 외래 키를 지키는 정도가 다릅니다: SQLite 는 외래 키 검사가 기본으로 꺼져 있어 PRAGMA foreign_keys = ON; 으로 연결마다 켜야 합니다. 외래 키를 적어 두었다고 늘 검사된다고 보지 마시고 쓰는 제품 문서를 확인하시길 권합니다.

외래 키가 없는 회원번호 주문은 막히고, 외래 키가 NULL 인 주문은 들어가는 모습을 비교한 그림 개념 그림: 외래 키는 없는 회원번호만 막고, 비어 있는 값은 막지 않습니다

마치며

기본 키는 행을 하나씩 구별하는 열, 외래 키는 그 기본 키를 가리켜 두 표를 잇는 열이고, 이 둘로 1:1·1:N·N:M 관계를 표현합니다. 엑셀에서 VLOOKUP 으로 찾아오던 회원번호가 데이터베이스에서는 약속으로 지켜진다고 생각하시면 이해가 쉬울 겁니다. 저도 시리즈를 따라가며 공부하고 있으니 전체 커리큘럼을 참고해 주세요. 다음 글에서는 표를 왜 여러 개로 나누는지, 정규화를 다룹니다.

자주 묻는 질문

기본 키와 외래 키의 차이는 무엇인가요?
기본 키는 자기 테이블의 행을 하나씩 구별하는 열로, 값이 겹치거나 비어 있으면 안 되고 테이블마다 최대 하나입니다. 외래 키는 다른 테이블의 기본 키(또는 UNIQUE 열) 값을 가리키는 열로, 가리키는 테이블에 없는 값은 넣을 수 없으며 한 테이블에 여러 개 둘 수 있습니다.
다대다(N:M) 관계는 어떻게 만드나요?
두 테이블 사이에 연결 표를 하나 더 만들고, 양쪽 테이블의 기본 키를 외래 키로 담습니다. 주문과 상품이라면 주문번호와 상품번호를 담은 주문 상품 표를 두고, 두 열을 묶어 기본 키로 삼는 방식이 PostgreSQL 문서에 예시로 나옵니다.
primary key(PK)는 꼭 있어야 하나요?
관계형 이론에서는 모든 테이블에 기본 키가 있어야 한다고 보지만, PostgreSQL 은 이를 강제하지 않습니다. 다만 같은 행이 두 번 들어가는 일을 막고 다른 표가 가리킬 대상이 되므로 두는 편이 대개 좋습니다.

관련 글 더 보기