• 카테고리

    질문 & 답변
  • 세부 분야

    데이터베이스

  • 해결 여부

    미해결

M : N 관계 질문드립니다.

21.05.25 06:11 작성 조회수 108

2

안녕하세요. 최근에 강의를 사서 매우 만족하며 듣고 있습니다.

들으면서 궁금한 점이 있어서 질문좀 드립니다.

예를 들어 학년과 반 테이블이 있다면,

제가 SpringJPA 를 공부하면서 배우기로는

한 학년에 여러 반이 존재하고, 한 반은 여러 학년에 존재할 수 있으므로 서로 1 : N 관계인 M : N 관계가 형성이 되는데요.

근데 이 강의를 접하고 나서는 굳이  중간 테이블을 하나 만들면서까지 M : N 관계를 고집하지 않아도 될 것 같더라구요.

예를들어 한 학년에는 여러 반이 존재하니, 

학년 테이블과 반 테이블을 1 : N 관계로 설정 하고, 

이번 강좌에서 한 것처럼 반 테이블에 외래키인 학년 ID 랑 반 ID를 같이 묶어서 PK로 만들면 PK가 중복될 일 없이 M : N 테이블 관계를 만든 것 처럼 역할을 할 수 있는것 같더라구요.

그래서 여기서부터 의문이 들었습니다.

실전에서는 M : N 관계라도 비즈니스 관계가 (예를 들면 이번 강의에서 "선생님" 이 "과목" 을 "개강하다." 처럼)

있는 것이 아니면 위에서 말한 학년 반 처럼 1 : N 으로 만들고 N 테이블 쪽에는 PK 를 묶어서 정의하나요?

그리고 이번 강의에서처럼 강사님처럼 "선생님" 이 "과목"을 "개강하다" 라는 문맥을 만들어서 비즈니스 관계를 찾는게 아직은 익숙하지가 않더라구요. 

혹시 요구사항문을 보고 이런 것을 빨리 캐치하는 팁 같은것은 없을까요? 당연히 반복된 연습이 제일 최고인 것은 알지만 혹시나 싶어서 질문드려봅니다.

좋은 강의를 정말 좋은 가격에 만들어주셔서 너무 감사드립니다. 

답변 1

답변을 작성해보세요.

3

예리한 질문을 주셔서 감사합니다. 다음 예를 같이 생각해보죠. 기계를 판매하는 대리점이 있습니다. 대리점은 여러 고객사를 거느리고 있고 고객사는 기계를 사용해서 무언가 생산을 하고 있습니다. 이 경우 대리점 AG와 고객사 CU는 M:N의 관계일까요 아니면 1:M의 관계일까요? 여기까지 읽고 생각한 다음 아래 설명을 읽어 주세요.

사실은 위의 경우 답이 없습니다. 다시 말하면 두 경우는 서로 다른 환경 - 가능성-을 설정해 놓게 됩니다. 우선 알기쉽게 1:M으로 설정한 경우 어떤 의미가 있는지 봅시다.  이들 관계는  "하나의 CU는 반드시 하나의 AG에 소속되어야 한다"는 제약조건을 아주 강력하게 가지고 있습니다. CU가 특정 대리점에 소속되는 이상 절대로 다른 대리점에는 소속될 수가 없습니다. 

그러나 이런 경우는 어떨까요? 거래 관계가 복잡해서 하나의 CU가 하나의 AG에 속하기는 하는데 시스템이 확장되면서 다른 물건을 파는 대리점을 관리해야 하는 상황입니다. 즉, CU는 삼성전자만 거래하다가 LG전자 물품도 거래하는 경우가 된거죠. 그러면 자연스럽게 M:N의 관계로 확장됩니다. 그래서 AG_CU라는 관계 테이블이 나타나게 되고 AG_CU 테이블의 PK는 AG_PK + CU_PK의 합이 되므로써 중복을 막으면서 고유성을 보장하게 되는 것입니다.

이와같이 1:M은 간단 명료한 경우 주로 사용됩니다. 회사 조직이 예가 될 수 있겠죠. 총무부->총부과(1,2,3)->총무팀(1.2.3.4) 등등. 자기 부모에 절대적으로 소속되고 다른 부모를 절대로 바라보지 않는 경우이지만 향후 확장성에는 약간의 문제가 있습니다. 즉, 전략 기획실이 생기면서 총무과 일부를 통제해야 하는 상황이 된다면 1:M의 표현으로는 한계가 있는 것이죠. 반면 M:N의 관계는 상상밖으로 복잡해 집니다. 프로그램을 개발하다보면 M:N의 관계가 있으면 JOIN 자체가 복잡해집니다. 나중에는 정신이 하나도 없을 만큼 만드는 본인도 헛갈릴 수 있을 만큼 다양성을 내포하고 있습니다. 따라서 설계 시 일을 간단하게 처리하려면 1:M으로 가는 것이 맞습니다. 그러나 확장성을 고려해야 하는 상황이라면 안전하게 M:N으로 묶어 주면 됩니다.

여기서 M:N으로 갔을 경우 대리점 AG1에 소속되는 CU들을 돌려받고 싶을 때 즉, AG_CU테이블의  내용을 반환하는 것이 아니라 AG1에 소속된 CU테이블의 내용을 돌려 받으려면 어떻게 해야 할까요?

select a.* from CU a INNER JOIN AG_CU b on a.id = b.id

where b.AGID = AG1

대충 이해하시면 됩니다. 포인트는 1:M은 JOIN 없이 하나의 부모에 소속된 자식을 where절로만으로 찾을 수 있지만 M:N의 경우 위와 같이 반드시 JOIN이 있어야 찾을 수 있습니다. 위의 쿼리는 실전에서 참 많이 사용하는데 의외로 잘 모르는 분들이 많습니다. a.*가 재미있는 부분입니다. 실전에서 관계 테이블은 JOIN문을 돕기 위해서 존재하는 것이지 그 테이블 값들이 직접 사용되는 경우는 거의 없습니다.

그럼 도움이 되시길 바랍니다. 

감사합니다.

Chang Moo Moon님의 프로필

Chang Moo Moon

2021.09.25

엄청나게 도움이 되는 답변입니다. 감사합니다