다대다 관계는 관계 자체를 하나의 레코드로 만들면 모델링하기 쉬워집니다. 한 수강생은 여러 강좌를 들을 수 있고, 한 강좌에는 여러 수강생이 참여할 수 있습니다. 수강생 행에 강좌 ID 목록을 저장하는 대신, 수강 등록 테이블에 개별 연결을 기록합니다.
데이터베이스 구현을 결정하기 전에 ER 다이어그램 작업 공간에서 관계를 정리해 보세요. 이 예시는 수강생과 강좌에서 시작해 연결 테이블을 추가한 뒤, 흔히 놓치는 조건인 ‘같은 강좌가 여러 번 개설될 수 있다’를 반영합니다.

수강 등록 한 행의 의미 정하기
교육 기관에서 ‘데이터 기초’와 ‘시각적 계획 수립’ 강좌를 제공한다고 가정해 봅시다. 수강생 S01은 두 강좌를 모두 듣고, S02는 데이터 기초를 듣습니다. 개념적으로는 다대다 관계입니다. 한 수강생이 여러 강좌와 연결되고, 각 강좌가 여러 수강생과 연결될 수 있습니다.
관계형 설계에서는 연결 테이블로 개별 연관 관계를 표현합니다. Microsoft의 다대다 관계 문서도 같은 패턴을 설명합니다. 연결 테이블의 각 행에는 양쪽 레코드를 가리키는 외래 키가 들어갑니다. 업무상의 관계는 다대다이지만, 이를 표현하는 테이블 간 연결은 일대다가 됩니다.
| student_id | course_id | 의미 |
|---|---|---|
| S01 | C10 | 수강생 S01이 데이터 기초에 등록했다. |
| S01 | C20 | 같은 수강생이 시각적 계획 수립에도 등록했다. |
| S02 | C10 | 다른 수강생이 데이터 기초에 등록했다. |
이 세 행은 중복된 수강생 레코드가 아닙니다. 수강생 정보는 Student, 강좌 정보는 Course에 두고, Enrollment는 두 대상의 연관 관계를 기록합니다. 수강생 이름의 오타를 수정하기 위해 모든 수강 등록을 하나씩 고칠 필요는 없습니다.
두 개의 일대다 연결 그리기
Student와 Course 사이에 Enrollment를 놓습니다. 먼저 단순화한 모델에서는 관계를 다음과 같이 표시합니다.
- 하나의 Student는 0개 이상의 Enrollment 행을 가질 수 있습니다.
- 각 Enrollment는 정확히 하나의 Student를 참조합니다.
- 하나의 Course는 0개 이상의 Enrollment 행을 가질 수 있습니다.
- 각 Enrollment는 정확히 하나의 Course를 참조합니다.
0개를 허용한다는 점이 중요합니다. 신규 수강생은 등록하기 전부터 존재할 수 있고, 새로 만든 강좌에는 아직 수강생이 없을 수 있습니다. 반면 수강 등록은 양쪽 대상이 모두 있어야 의미가 있으므로, 이 모델에서는 두 외래 키 필드를 필수로 둡니다.
물리 테이블 다이어그램에 Student와 Course를 직접 잇는 선도 남기려면 그 선이 다른 의미임을 분명히 해야 합니다. 그렇지 않으면 연결 테이블을 통한 관계와 별도의 직접 연결을 모두 구현하라는 뜻으로 보일 수 있습니다. 개념적 개요에서는 다대다 관계를 보여 주고, 테이블 수준의 그림에서는 이를 어떻게 표현하는지 설명합니다.
관계에 속하는 필드를 Enrollment에 배치하기
그 값이 수강생을 설명하는지, 강좌를 설명하는지, 아니면 이 수강생이 이 강좌에 참여한 사실을 설명하는지 물어보세요. 많은 필드의 위치를 이 질문으로 정할 수 있습니다.
| 필드 | 배치할 테이블 | 이유 |
|---|---|---|
| student_name | Student | 수강 등록마다 이름이 달라지는 것은 아닙니다. |
| course_title | Course | 이름은 강좌를 설명하지, 개별 참석자를 설명하지 않습니다. |
| enrolled_at | Enrollment | 이 연관 관계가 시작된 시점을 기록합니다. |
| enrollment_status | Enrollment | 한 수강생이 한 강좌를 취소해도 다른 강좌는 계속 수강할 수 있습니다. |
| completion_result | Enrollment | 결과는 이 수강생의 참여에 속하며, 해당 강좌를 듣는 모든 수강생에게 공통된 값이 아닙니다. |
연결 테이블에는 ID 두 개만 들어가야 하는 것은 아닙니다. 이 예시는 관계에 상태와 이력이 있으므로, 수강 등록을 뜻하는 Enrollment가 유용한 업무 명칭입니다. StudentCourse라는 이름도 가능하지만, 레코드가 무엇을 의미하는지 가리지 않아야 합니다.
수명 주기도 명확히 하세요. 수강을 취소하면 상태를 바꿀지 별도 이벤트를 기록할지 정합니다. 행을 삭제하면 해당 관계의 이력이 사라집니다. 적절한 보존 정책은 애플리케이션에 따라 다릅니다. 모든 취소를 삭제로 간주하지 말고, 합의한 모델을 다이어그램에 표시해야 합니다.
키와 유일성 규칙을 따로 정하기
수강생과 강좌의 조합마다 한 번만 등록할 수 있다면 (student_id, course_id)를 복합 기본 키로 사용할 수 있습니다. 두 값의 조합이 한 행을 식별한다는 뜻이며, 각 열이 단독으로 유일할 필요는 없습니다.
다른 방법은 별도의 enrollment_id를 기본 키로 두고 수강생과 강좌의 조합에 유일 제약 조건을 거는 것입니다. ID를 하나 더 만든다고 S01이 C10에 두 번 입력되는 일이 저절로 방지되지는 않습니다. 중복 관계가 허용되지 않는다면 그 규칙을 명시하세요.
PostgreSQL의 제약 조건 문서는 기본 키, 유일 제약 조건, 외래 키를 구분합니다. 이 예시에서 외래 키는 참조하는 수강생과 강좌가 존재하도록 하고, 유일성 규칙은 같은 관계가 반복되는 것을 막습니다. 기본 키는 행을 식별합니다. 서로 관련된 역할이지만 바꿔 쓸 수 있는 라벨은 아닙니다.
다이어그램은 규칙을 문서화하고, 데이터베이스는 그 규칙을 강제해야 합니다. 선에 ‘1’을 표시하거나 ‘유일’이라고 적어도, 구현에 반영되지 않았다면 애플리케이션이 잘못된 데이터를 쓰는 것을 막지 못합니다.
같은 강좌가 다시 개설되는 경우 처리하기
데이터 기초가 봄과 가을에 열리면 단순한 조합은 지나치게 제한적입니다. S01이 다시 수강할 수 있다면 (student_id, course_id)는 의도한 유일성 규칙을 나타내지 못합니다. 그렇다고 유일성을 완전히 없애면 같은 개설 회차에 실수로 중복 등록하는 것도 허용하게 됩니다.
강좌가 한 번 개설되는 회차를 나타내는 CourseOffering을 도입합니다. 강좌 C10에 봄 회차 O101과 가을 회차 O102가 있다고 가정해 봅시다. 각 회차는 하나의 Course를 참조하고, 하나의 Course는 여러 회차를 가질 수 있습니다. 이제 Enrollment는 Student와 CourseOffering을 연결합니다.
등록 조합은 (student_id, offering_id)가 됩니다. S01–O101과 S01–O102는 서로 다른 등록이므로 둘 다 유효할 수 있습니다. 수강생별로 한 회차에 한 번만 등록할 수 있다는 규칙이라면 두 번째 S01–O101은 여전히 중복입니다.
시작일처럼 회차에 속하는 정보는 Course가 아니라 CourseOffering에 둡니다. 강좌명은 반복해서 제공할 강좌를 설명하고, 개설 회차는 언제 진행하는지를 설명합니다. 한 회차 안에서 여러 번 참여하거나 응시할 수 있는 서비스라면 등록 키를 계속 느슨하게 바꾸지 말고, 그 추가 개념을 명시적으로 모델링하세요.
Boardmix에서 구체적인 레코드로 모델 검토하기
Boardmix 캔버스에 Student, Enrollment, CourseOffering, Course를 네 개의 엔터티 상자로 그립니다. Enrollment를 Student와 CourseOffering 사이에 놓고, CourseOffering을 Course와 연결하세요. 필드명 옆에 기본 키와 외래 키를 표시하고, 수강생과 개설 회차 조합의 유일성은 별도의 메모로 남깁니다.
그림 아래에 S01–O101, S01–O102, 반복된 S01–O101이라는 등록 카드 세 개를 놓습니다. 앞의 두 개는 서로 다른 관계로, 반복된 조합은 선택한 규칙에서 중복으로 표시하세요. 필드명 목록만 보는 것보다 모델의 동작을 논의하기 쉽습니다.

Boardmix에서 보드를 열고 자신의 업무 영역에 해당하는 레코드 몇 개로 관계를 확인해 보세요. 새 부모 레코드에 연관 관계가 없어도 되는지, 같은 조합이 다시 나타나도 되는지, 관계에 속하는 값은 어디에 들어가야 하는지 생각해 봅니다.
답에 따라 다이어그램이 달라질 수 있습니다. 이 교육 기관에서 중요한 발견은 세 번째 테이블이 필요하다는 사실만이 아닙니다. 수강 등록은 수강생을 추상적인 강좌와 영구히 연결하는 것이 아니라, 특정 개설 회차와 연결한다는 점입니다.