데이터과학 유망주의 매일 글쓰기 — 열한 번째 일요일

배우는 자(Learner Of Life)
10 min readNov 22, 2020

--

북유럽 신화로 보는 N:N관계

# 북유럽 신화, #dbdiagram, #데이터베이스, #관계

바이킹족의 고대 북유럽 신화를 통해 N:N관계를 엿보자.

오늘 한일:

어제는 SQL기반 관계형 데이터베이스에서 고려해야할 가장 중요한 요소들에 대해 다루어 보았다. 이번 주에 또 아쉬웠던 점은 관계형 데이터베이스를 과제에서 표현하는데 있어 조금 미흡했다는 피드백을 받은 것이었다. 그래서 이를 좀 보완하기 위해, dbdiagram.io라는 웹사이트를 이용하여 나만의 데이터베이스 사이 관계를 보여주는 ERD(Entity Relationship Diagram)을 작성해보았다.

내가 좋아하는 북유럽 신화의 캐릭터들의 관계를 바탕으로 관계형 데이터베이스에서 있을 수 있는 여러가지 관계에 대해 설명해보고자 한다.

관계형 데이터베이스의 예

1: 1 관계

먼저 1:1 관계에 대한 예를 보자. 각 캐릭터에 대한 ID와 이름을 가진 characters 라는 테이블을 가정하자. 각 캐릭터를 구분하기 위해 CharacterId라는 칼럼이 있다. 이 칼럼의 각 값들에 대해 CharacterName이라는 칼럼에 각 캐릭터의 이름이 맵핑되어있다. 각 ID는 하나의 캐릭터의 이름만 가질 수 있고, 각 캐릭터도 하나의 ID값 만을 가질 수 있기 때문에 CharacterId와 ChracterName은 서로 1:1관계라 할 수 있다. 또한 한 테이블 안에서 정의되는 관계이므로 자가 참조(self-referencing)관계이다.

characters 테이블 안에 서로 1:1 관계에 있는 두 칼럼

1:N 관계

각 캐릭터들의 종족(tribes)에 대한 정보를 담은 tribes라는 테이블을 가정한다. 여기서 각 종족은 TribeId칼럼의 값으로 구분된다. “A”는 “Aesir”, “B”는 “Vanir”, “C”는 “Giants”라고 하자. 이 테이블의 TrbieId는 역시 characters테이블에도 존재한다고 하자. 각 캐릭터가 어떤 종족인지 이 TribeId의 값으로 나타낼 수 있는데, 각 캐릭터는 하나의 종족만이 될 수 있지만, 각 종족은 여러 캐릭터를 가질 수 있으므로, 이 경우 1:N관계가 성립한다. tribes테이블의 TribeId와 characters테이블의 TribeId는 1:N의 관계로 볼 수 있다.

tribes의 TribeId와 characters의 TribeId는 서로 1:N의 관계에 있다.

N:N관계

북유럽 신화에서는, 반은 사람이고 반은 거인인 Odin같은 캐릭터도 존재하고, 원래는 거인이었으나 신으로 받아들여진 Loki, Skadi같은 캐릭터들도 있다. 각 캐릭터의 타입이 신(God), 여신(Goddess), 거인(Giant), 거인여성(Giantess)인지를 나타내는 types테이블이 존재한다고 가정하자. 여기서 “A”가 신이며, “B”가 여신, “C”가 거인, “D”가 거인 여성을 나타내는 TypeId라는 칼럼이 있다고 하자. 이 정보 역시 characters 테이블에 같은 이름으로 존재하는데, 각 캐릭터는 다수의 타입을 가질 수 있다. 즉, 각 캐릭터가 하나 이상의 타입을 가질 수 있므며, 각 타입의 입장에서도 여러 캐릭터를 가지는 것이 가능하다. types테이블의 TypeId와 chracters테이블의 TypeId는 N:N의 관계라고 볼 수 있다.

characters의 캐릭터들은 다수의 타입을 가질 수 있고, types의 TypeId역시 여러 캐릭터를 가질 수 있는 N:N관계다.

이 내용을 바탕으로 생성된 테이블을 아래와 같다.

tribes, types, chacters 테이블의 전체모습

이제 dbdiagram.io을 사용해서 이 모든 관계들을 정의해야 하는데, 이 도구는 직접적인 N:N관게를 풀어낼 수 없다는 단점이 있다. 그러므로, characters 테이블의 CharacterId와, types테이블의 TypeId칼럼을 가져와 “characters_types”라는 테이블을 새로 생성하였다.

N:N 관계를 위해, characters 테이블의 CharacterId와 types테이블의 TypeId정보를 따로 테이블로 만들었다.

이제 테이블의 관계를 표현하는 ERD를 생성하기 위한 모든 작업을 마쳤다. 아래는 dbdiagram에서 위 테이블을 생성하기 위한 코드이다.

//// -- LEVEL 1
//// -- Tables and References
// Creating tables
Table characters as ch {
CharacterId int [pk, increment] // auto-increment
CharacterName varchar
TribeId varchar
TypeId int
}
Table tribes as tr {
TribeId varchar [pk]
TribeName varchar
}

Table chracters_types as chty{
CharacterId int [pk]
TypeId varchar [pk]
}
Table types as ty {
TypeId varchar [pk]
TypeName varchar
}
// Creating references
// You can also define relaionship separately
// > many-to-one; < one-to-many; - one-to-one
Ref: tr.TribeId > ch.TribeId
Ref: ch.CharacterId - ch.CharacterName
Ref: chty.CharacterId - ch.CharacterId
Ref: chty.TypeId - ty.TypeId
//----------------------------------------------//

위 코드를 바탕으로 생성된 최종 ERD는 아래와 같다.

완성된 전체 ERD의 모습

이전에 언급한 것처럼, characters테이블안에서 CharacterID는 CharacterName과 1:1로 맵핑되어있는 자가참조(self-referencing)관계이다. tribes테이블의 TribeId를 Primary Key로 사용하고, characters의 TribeId는 Foreign Key로 사용되었다. 이 과정에서 tribes 테이블의 TribeId는 characters테이블의 TribeId와 1:N 관계를 갖는다.

또한, chacters_types 테이블의 CharacterId를 Primary로 사용하여 characters 테이블의 Foreign Key인 CharacterId로 연결했다. 이 과정에서 characters_types테이블과 characters테이블간의 1:1 관계가 성립되었다. 또한 characters_types 테이블의 TypeId를 Primary Key로 하여, types테이블의 TypeId의 Foreign Key와 연결하였다. 여기서도 characters_types와 types테이블간의 1:1관계가 성립되었다.

characters_types 테이블 안에서는 CharacterId와 TypeId의 관계가 N:N으로 설정되어있으므로, 자연스럽게 이 테이블이 이어주는 characters테이블의 CharacterId칼럼과 types테이블의 TypeId의 관계가 N:N의 관계가 된다.

앞으로 할일:

오늘은 지난 과제 중 미흡했던, N:N관계를 포함한 관계형 테이블의 ERD를 만들어 보았다. N:N테이블은 “서로 N:N관계를 갖는 특정한 두 테이블의 칼럼 정보를 가져와 새로운 테이블을 형성하여, 중간에서 각각 원래 칼럼을 가진 두 테이블을 1:1관계로 이어주는 테이블"을 통해 표현할 수 있음을 확실히 알게되었다.

무엇보다도, N:N관계를 가장 확실하게 표현할 수 있는 관계는 “불륜관계"라는 생각이 들었다. 사실 위 북유럽 신화의 예에서, 최고신인 오딘(Odin)은 프레이야(Freya)와 프리그(Frigg)라는 두 명의 아내를 거느렸다. 만약, Freya와 Frigg역시 다른 젊은 남신과 염문이 있었다면 이는 N:N관계로 확실히 말할 수 있다. 한 신이 여러명의 아내를 거느리거나, 그 신의 아내인 여신이 여러 다른 남신들과 관계를 맺을 수도 있기 때문이다. (물론 여신이 그렇게 한다면 남성위주의 당시 문화에서 절대 받아들여질 수 없을 이야기였을 테지만.) 다행이도 이런 “다대다(N:N)"의 관계는 데이터베이스를 사용함에 있어 그렇게 자주 나타나지는 않는다고 하니 마음이 놓인다.

한 주 동안 배운것들 중 분명히 내가 확실하게 알고 넘어가지 못한 것들이 있다. 그것들에 대해서는 이렇게 주말을 이용해서 만회해보려 노력한다. 그래서 이렇게 휴식을 취하면서 내가 확실히 모르고 넘어간 것을 리뷰해 볼 수 있는 시간이 매주 주어진다는 것에 감사하다. 앞으로도, 내가 한 주동안 배운 것들 중에 제대로 학습하지 못한 것들에 대해서 이렇게 주말을 이용해서 블로그를 써보면서, 내가 부족한 것들을 채워나갈 생각이다. “글을 쓰기 위해 공부를 한다.”라고도 볼 수 있겠다. 나중에 나뿐만 아니라 내 글을 읽을 그 누군가에게 도움이 될 목적으로 정확하고도 알기쉬운 정보를 전달하는 글을 쓰고싶다. 덕분에 그 것이 좋은 동기부여가 되어, 내가 글을 쓰고자하는 주제에 대해 충분히 잘 설명할 수 있을 정도로 공부하게 되는 것 같다. 블로깅을 이렇게 좋은 학습도구로 활용할 수 있을지 처음에는 잘 몰랐지만, 계속 글을 쓰면서 주제에 대해 생각해보고 나의 언어로 정리하게된다. 결과적으로, 스스로 한 주제에 대해 더 깊은 학습을 하게된다. 부가적으로, 나중에 내가 필요할 때 찾아볼 수 있는 좋은 기록물이되고, 나중에 나의 이력서에 활용될 수 있는 일종의 포트폴리오가 될 것이다. 내가 “이 만큼 매일 꾸준히 노력했습니다!”라고 자신있게 말할 수 있는 증거가 될 거라 믿는다.

내일부터 이어지는 새로운 과정도 잘 학습할 수 있기를, 블로깅을 멈추지 않고 계속 유용한 학습의 도구로 삼을 수 있기를 스스로 다짐해본다. 내가 매일 쓰는 모든 글들이 나의 찬란하고 열정적인 청춘의 역사가 될 수 있도록.

참조:

(1) dbdiagram.io

(2) dbdiagram tutorial

--

--

배우는 자(Learner Of Life)
배우는 자(Learner Of Life)

Written by 배우는 자(Learner Of Life)

배움은 죽을 때까지 끝이 없다. 어쩌면 그게 우리가 살아있다는 증거일지도 모른다. 배움을 멈추는 순간, 혹은 배움의 기회가 더 이상 존재하지 않는 순간, 우리의 삶은 어쩌면 거기서 끝나는 것은 아닐까? 나는 배운다 그러므로 나는 존재한다. 배울 수 있음에, 그래서 살아 있음에 감사한다.

No responses yet