RDBでテーブルの作り方が良くわからなくなってきたので、いったんまとめてみた

カーディナリティや依存関係*1、関係テーブル、正規化など、曖昧な知識のままなので、ちょっとまとめてみます。
経験からなんとなくは分かっているつもりですが、このままだと誰かに説明することもできないし、間違いに気がつかないかもしれない。
一度アウトプットすると整理されるらしいし、間違ってるかもしれないけど書いちゃいます。
なので、つっこみ歓迎です。

題材があったほうが書きやすいので、サンプルのER図を作りました。

  • ユーザーとそのプロフィール。
  • ユーザーが投稿した記事。
  • 記事にフォークソノミーなタグ付け。

こんなデータが格納できる、簡易ブログというか簡易SNSの一部分といったイメージです。

カーディナリティ

エンティティ*2間の関係。

一対一 (one-to-one)
[user] と [profile] の関係。ユーザー1人にプロフィールも1個。*3
一対多 (one-to-many)
[user] と [post] の関係。ユーザー1人が、記事を0個以上からn個まで投稿していきます。
多対多 (many-to-many)
[tagged] という関係テーブルを介した [post] と [tag] の関係。記事に対して0個からn個までのタグが付くし、とあるタグが0個からn個の記事に付けられます。

関係テーブル

リレーショナルデータベースでは、多対多の関係をそのまま作れないので、一対多に分解します。
その際、2個に分けたテーブルの対照表が必要になり、それが関係テーブルです。


関係テーブルは実体がなく、ER図では多対多を表すこともできます。
なので、ER図では関係テーブルは書かず、RDB上に実装する際に作るという意見も見かけたけど、ER図に書いちゃったほうが分かりやすいという意見も。
書いちゃったほうが分かりやすいですね。


非正規形を第1正規形にして、さらに第2正規形にすると、関係テーブルが出来上がってたりするみたい。
断言した解説があったわけじゃないけど、色々調べてたらなんとなくそうなってるかなと。

ER図について

ER図の記述法にはいくつかあるようで、よく見かけるのはIE*4表記とIDEF1Xです。
サンプルはIE表記で作ってます。


余談だけど、どちらの記述法もカーディナリティを形で表します。
クラス図の多重度みたいな表現にしてくれれば分かりやすいのに。

依存関係

いろいろ英語のサイトも調べた結論(今のところ)

独立なら:
子エンティティは角の尖った四角形で書き、関係は点線で書く。
子エンティティは主キーに親エンティティーを外部キーとして持たない。

依存なら:
子エンティティは角の丸い四角形で書き、関係は実線で書く。
子エンティティは主キーに親エンティティーを外部キーとして持つ。

みたい。なんで角の尖った四角形の場合は必ず関係は点線で書く。世の中にそうなってない解説ページが山程あるんで自信ないけど。

追記:

あーたぶんわかった。依存エンティティでもエンティティへの外部キーを主キー以外にもってるのもあるから、そういうのは点線で書くのか。

http://d.hatena.ne.jp/name-3333/20090219/1234992493

まとまった記事があったので引用です。
四角形で書き〜〜のあたりはIDEF1Xで書いたER図の話なので置いといて、主キーと外部キーのところがポイント。
サンプルでいうと [profile] が [user] に依存してます。
[user] が親で [profile] が子です。


エンティティの依存関係について - kanonjiの日記
エンティティの依存関係について、追加で調べてみました。
でも、少し分かった気がしたんですが、新たな疑問も出てきちゃってます。

関係テーブルはどうする?

[post] と [tag] の関係テーブルである [tagged] ですが、これを独立にするか依存にするが良く分からない。
id_post と id_tag のどちらも、[tagged] 内ではユニークにはならないので、id というプライマリーキーを作ってます。
そうすると、[tagged] は独立という事になります。
でも id_post と id_tag での複合プライマリーキーを作れば、id が要らなくなるので依存にもできるかなと。
ちゃんと基底から理解してないから、分からなくなるんだろうけど。



主キーには人工キーを使うか自然キーを使うか - kanonjiの日記
id という主キーを作るか、複合キーで主キーを作るかは、この人工キー or 自然キーのどちらの方針にするかに寄るみたいです。

*1:親子関係とも

*2:≒クラス図におけるオブジェクト

*3:このサンプルの場合プロフィールは無しにも出来るので、厳密にはプロフィールは0 or 1ですが。

*4:Information Engineering。なぜかWikipediaにページがない。