CodeGym /행동 /SQL SELF /중간 테이블을 이용한 MANY-TO-MANY 관계 모델링

중간 테이블을 이용한 MANY-TO-MANY 관계 모델링

SQL SELF
레벨 19 , 레슨 4
사용 가능

"many-to-many" 관계는 한 테이블의 한 레코드가 다른 테이블의 여러 레코드와 연결될 수 있고, 반대로도 가능한 거야. 예를 들어: - 한 학생(students 테이블에서)이 여러 과목(courses 테이블에서)을 수강할 수 있어. - 한 과목도 여러 학생이 들을 수 있지.

근데 이런 관계를 직접 테이블에 저장하려면 진짜 불편해. 그래서 중간 테이블이 등장해서 이 관계들을 저장해주는 거야.

실생활 예시

학생 테이블이랑 과목 테이블을 만들었다고 생각해봐. 만약 각 테이블에 모든 관련 데이터를 저장하려고 하면 완전 난장판이야:

  • students 테이블에 학생이 듣는 모든 과목 리스트를 저장해야 해. 근데 리스트를 어떻게 저장하지? 콤마로 구분? 배열로? 쿼리 짜기 엄청 힘들어질 거야.
  • courses 테이블에 학생 리스트를 저장해야 하는데, 이건 진짜 머리 아파.

그래서 정답은 — 학생과 과목 사이의 관계를 저장하는 세 번째 테이블을 만드는 거야.

중간 테이블: 우리의 구세주!

중간 테이블(가끔 관계 테이블이라고도 해)은 모든 문제를 해결해줘. 이 테이블에는 두 개의 외래 키가 있어:

  • students 테이블을 참조하는 외래 키.
  • courses 테이블을 참조하는 외래 키.

이 테이블의 각 레코드는 특정 학생과 특정 과목 사이의 관계를 만들어줘.

"many-to-many" 관계를 위한 테이블 만들기

이제 실습해보자! 학생과 과목 사이의 관계를 위한 테이블을 이렇게 만들 수 있어:

1단계: students 테이블 만들기

이게 학생 테이블이야. 여기서 학생의 고유 ID랑 이름을 저장해.

CREATE TABLE students (
    student_id SERIAL PRIMARY KEY,
    name TEXT NOT NULL
);
  • student_id — 학생의 고유 식별자야(SERIAL 덕분에 자동 증가!).
  • name — 학생 이름.

2단계: courses 테이블 만들기

이제 과목 테이블을 만들어보자. 여기서 과목의 고유 ID랑 이름을 저장해.

CREATE TABLE courses (
    course_id SERIAL PRIMARY KEY,
    title TEXT NOT NULL
);
  • course_id — 과목의 고유 식별자.
  • title — 과목 이름.

3단계: 중간 테이블 enrollments 만들기

이제 우리의 마법 같은 관계 테이블을 만들어보자. 이 테이블에는 두 개의 컬럼이 있는데, 각각은 해당 테이블을 참조하는 외래 키야.

CREATE TABLE enrollments (
    student_id INT REFERENCES students(student_id),
    course_id INT REFERENCES courses(course_id),
    PRIMARY KEY (student_id, course_id)
);

구조를 살펴보면:

  • student_idstudents 테이블의 student_id를 참조하는 외래 키.
  • course_idcourses 테이블의 course_id를 참조하는 외래 키.
  • PRIMARY KEY (student_id, course_id) — 두 외래 키 조합이 기본 키야. 이걸로 각 관계가 유일하게 보장돼.

데이터 삽입하기

이제 데이터 좀 넣어서 어떻게 돌아가는지 확인해보자.

1단계: 학생 추가하기

INSERT INTO students (name) VALUES
('Alice'),
('Bob'),
('Charlie');

결과:

student_id name
1 Alice
2 Bob
3 Charlie

2단계: 과목 추가하기

INSERT INTO courses (title) VALUES
('Mathematics'),
('History'),
('Biology');

결과:

course_id title
1 Mathematics
2 History
3 Biology

3단계: enrollments에 데이터 넣기

이제 학생들을 과목에 등록시켜보자. 예를 들어:

  • AliceMathematicsHistory를 듣고 있어.
  • BobBiology만 듣고 있어.
  • Charlie는 세 과목 다 듣고 있어.
INSERT INTO enrollments (student_id, course_id) VALUES
(1, 1), -- Alice가 Mathematics 듣는 중
(1, 2), -- Alice가 History 듣는 중
(2, 3), -- Bob이 Biology 듣는 중
(3, 1), -- Charlie가 Mathematics 듣는 중
(3, 2), -- Charlie가 History 듣는 중
(3, 3); -- Charlie가 Biology 듣는 중

결과:

student_id course_id
1 1
1 2
2 3
3 1
3 2
3 3

"many-to-many" 관계를 위한 쿼리

이제 데이터가 있으니, 제대로 써먹어보자!

특정 학생이 듣는 모든 과목 찾기

예를 들어, Alice(ID = 1)가 듣는 과목을 알고 싶으면 이렇게 쿼리하면 돼:

SELECT c.title
FROM courses c
JOIN enrollments e ON c.course_id = e.course_id
WHERE e.student_id = 1;

결과:

title
Mathematics
History

특정 과목을 듣는 모든 학생 찾기

예를 들어, Mathematics(ID = 1)를 듣는 학생이 누군지 알고 싶으면:

SELECT s.name
FROM students s
JOIN enrollments e ON s.student_id = e.student_id
WHERE e.course_id = 1;

결과:

name
Alice
Charlie

학생과 그가 듣는 과목 전체 보기

누가 어떤 과목을 듣는지 전체적으로 보고 싶으면 이렇게 쿼리해:

SELECT s.name AS student, c.title AS course
FROM students s
JOIN enrollments e ON s.student_id = e.student_id
JOIN courses c ON e.course_id = c.course_id;

결과:

student course
Alice Mathematics
Alice History
Bob Biology
Charlie Mathematics
Charlie History
Charlie Biology

enrollments 테이블 덕분에 스키마가 엄청 유연해져 — 학생과 과목 사이의 관계를 쉽게 추가하거나 삭제할 수 있고, 원본 테이블은 건드릴 필요 없어. JOIN 쿼리로 누가 어떤 과목을 듣는지 쉽게 찾을 수 있고, 외래 키가 있어서 실수로 존재하지 않는 과목에 학생을 등록하는 일도 막아줘.

"many-to-many" 관계에서 흔한 실수

유일성 제약 없음: PRIMARY KEY를 안 걸면 같은 관계가 여러 번 들어갈 수도 있어.

데이터 무결성 깨짐: 없는 student_idcourse_id로 레코드를 넣으려고 하면 에러 나.

삭제 순서 실수: courses에서 과목을 먼저 지우면 enrollments에 "고아" 레코드가 남아. 이걸 막으려면 외래 키 정의에 ON DELETE CASCADE를 써줘야 해.

2
과제
SQL SELF, 레벨 19, 레슨 4
잠금
다대다(Many-to-Many) 관계를 위한 테이블 생성
다대다(Many-to-Many) 관계를 위한 테이블 생성
2
과제
SQL SELF, 레벨 19, 레슨 4
잠금
사용자와 프로젝트 간의 관계 가져오기
사용자와 프로젝트 간의 관계 가져오기
1
설문조사/퀴즈
외래 키, 레벨 19, 레슨 4
사용 불가능
외래 키
외래 키
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION