데이터과학 유망주의 매일 글쓰기 — 열한 번째 일요일
북유럽 신화로 보는 N:N관계
# 북유럽 신화, #dbdiagram, #데이터베이스, #관계
오늘 한일:
어제는 SQL기반 관계형 데이터베이스에서 고려해야할 가장 중요한 요소들에 대해 다루어 보았다. 이번 주에 또 아쉬웠던 점은 관계형 데이터베이스를 과제에서 표현하는데 있어 조금 미흡했다는 피드백을 받은 것이었다. 그래서 이를 좀 보완하기 위해, dbdiagram.io라는 웹사이트를 이용하여 나만의 데이터베이스 사이 관계를 보여주는 ERD(Entity Relationship Diagram)을 작성해보았다.
내가 좋아하는 북유럽 신화의 캐릭터들의 관계를 바탕으로 관계형 데이터베이스에서 있을 수 있는 여러가지 관계에 대해 설명해보고자 한다.
관계형 데이터베이스의 예
1: 1 관계
먼저 1:1 관계에 대한 예를 보자. 각 캐릭터에 대한 ID와 이름을 가진 characters 라는 테이블을 가정하자. 각 캐릭터를 구분하기 위해 CharacterId라는 칼럼이 있다. 이 칼럼의 각 값들에 대해 CharacterName이라는 칼럼에 각 캐릭터의 이름이 맵핑되어있다. 각 ID는 하나의 캐릭터의 이름만 가질 수 있고, 각 캐릭터도 하나의 ID값 만을 가질 수 있기 때문에 CharacterId와 ChracterName은 서로 1:1관계라 할 수 있다. 또한 한 테이블 안에서 정의되는 관계이므로 자가 참조(self-referencing)관계이다.
1:N 관계
각 캐릭터들의 종족(tribes)에 대한 정보를 담은 tribes라는 테이블을 가정한다. 여기서 각 종족은 TribeId칼럼의 값으로 구분된다. “A”는 “Aesir”, “B”는 “Vanir”, “C”는 “Giants”라고 하자. 이 테이블의 TrbieId는 역시 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의 관계라고 볼 수 있다.
이 내용을 바탕으로 생성된 테이블을 아래와 같다.
이제 dbdiagram.io을 사용해서 이 모든 관계들을 정의해야 하는데, 이 도구는 직접적인 N:N관게를 풀어낼 수 없다는 단점이 있다. 그러므로, characters 테이블의 CharacterId와, types테이블의 TypeId칼럼을 가져와 “characters_types”라는 테이블을 새로 생성하였다.
이제 테이블의 관계를 표현하는 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는 아래와 같다.
이전에 언급한 것처럼, 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