データモデリングでは、ER図がエンドユーザと設計者の、あるいは設計者と開発者の間のコミュニケーションツールとなります。
ER図は、エンティティ、リレーションシップ、属性、識別子という4つの要素から構成されています。そして、これらの要素は、テーブル、外部キー、列、主キーになります。
| ER図の構成要素 | データベースの要素 |
|---|---|
| エンティティ | テーブル |
| リレーションシップ | 外部キー |
| 属性 | 列 |
| 識別子 | 主キー、インデックス |
ところで、ER図の表記方法は一通りではありません。次のようなものがあります。
ここでは、IE表記法で説明していきます。
では、ER図の構成要素をもう少し詳しく見ていきましょう。
エンティティとは、「企業や業務が関心を持つ長期的に管理対象となり得るもの」であり、「その性質や意味を表す複数のデータ項目を持ち、特定のデータ項目により識別することが可能なもの」です。簡単にいえば、「データベースとして表現すべき対象物」です。
たとえば、販売管理システムにおいての「受注先、受注日、受注金額などの複数の項目を持ち、受注番号で識別できる、長期的に管理する『受注』」というものがあれば、それがエンティティです。
エンティティは、ER図では、角のある四角形や角の丸い四角形を用いて表します。エンティティ名は四角形の上に記述します。
角の丸い四角形が従属エンティティ(依存エンティティ)で、角のある四角形が独立エンティティ(基本エンティティ、非従属エンティティ)を表しています。これらの違いは識別子にあります。
(FK) は、他のエンティティの主キーと関連付く識別子や属性を示す(外部キーと呼ぶ)
エンティティが存在するためにはほかのエンティティの存在が必須となるようなエンティティ
識別子のすべて、あるいは一部に、他のエンティティの識別子や属性を持つ。
独立して存在できるエンティティ
識別子として、なんら他のエンティティの識別子や属性を持たない。
エンティティを作成した後にそれらを見直してみると、他のエンティティと識別子が同じで一部の属性だけが異なっているエンティティが存在していることに気がつくことがあります。このような場合に共通の属性だけを持つエンティティをスーパータイプ、固有の属性を持つエンティティをサブタイプと呼びます。
あらためて「販売先」エンティティの属性を見直してみましょう。「取引先番号」「取引先名」「郵便番号」「住所」の他に、どれだけ販売してよいかを管理するための「信用限度額」を持っています。
次に、「仕入先」エンティティの属性を検討してみましょう。販売のための属性である「信用限度額」は必要ありませんが、「支払い条件」などの仕入れのための属性が必要となってきます。しかし、「取引先番号」「取引先名」「郵便番号」「住所」などの属性は、「販売先」エンティティと同様に必要です。
そこで、 「取引先番号」「取引先名」「郵便番号」「住所」などの共通な属性だけを持つスーパータイプと、それぞれ固有の属性のみを持つサブタイプに分けて表現します。
「取引先番号」「取引先名」「郵便番号」「住所」などの共通な属性だけを持つようなエンティティ
固有の属性のみを持つエンティティ
リレーションシップとは、「2つのエンティティの間の意味ある関連を表現するもの」です。たとえば、「販売先」エンティティと「受注」エンティティの間には、「販売する」という関係が成り立ちますが、この「販売する」というのが、リレーションシップです。
リレーションシップは、関係のあるエンティティとエンティティの間に線を引いて表現します。 「販売先」エンティティと「受注」エンティティの関係を表すと図のようになります。
リレーションシップの両端には、カーディナリティ(種類の数)とオプショナリティ(任意性)を定義します。カーディナリティとは、リレーションシップのそれぞれの側にある「種類の数」を表現しています。そして、オプショナリティは、必須かどうかを表現します。
| 説明 | 例 | |
|---|---|---|
| 相手のエンティティのデータに対して、この終端に接続されるエンティティのデータは存在しないこともあるし、複数存在することもある。 | 社員に対する部下など | |
| 相手のエンティティのデータに対して、この終端に接続されるエンティティのデータは必ず1個以上存在する。 | 受注に対して受注明細など | |
| 相手のエンティティのデータに対して、この終端に接続されるエンティティのデータは存在しないか1個だけ存在する。 | 社員に対する上司など(普通は上司が一人いる。でもおそらく社長には上司はいない) | |
| 相手のエンティティのデータに対して、この終端に接続されるエンティティのデータは必ず1個存在する。 | 受注に対して顧客など(顧客の存在しない受注はありえない。顧客の複数ある受注もありあえない) |
リレーションシップでつながれた2つのエンティティがお互いに1つずつ対応している状態です。
1対1のパターンは図のとおりですが、あまり描かれることはありません。なぜなら、実装するときには一つのテーブルにまとめられることが多いからです。しかし、 1対1のリレーションシップが不要なわけではありません。
例えば、データが発生する時間が同じ場合は (1)パターン、発生する順序が決まっている場合は (2)パターン(この場合は左側が先に発生している)、どちらが先に発生しても構わない場合は (3)パターンというように考えます。
| 説明 | ||
|---|---|---|
| (1) | 両方向必須 データの発生が同時である |
|
| (2) | 片方向任意 データの発生する順番が決まっている |
|
| (3) | 両方向任意 データの発生する順番が決まっていない |
|
データが発生する時間が同じ場合です。このパターンは両方向必須なので、これは1つのエンティティとして設計することも多くなります。
例えば、「報告書」エンティティとその発生を知らせる「通知」エンティティがこれに当たります。報告書データを作成すると同時に、そのデータ作成の完了を知らせる「通知」データも作成されます。
データの発生する順番が決まっている場合です。
例えば、社内で開催される、社員が講師を担当するセミナーのような場合です。(この例では、社員の負担を減らすため、一人の社員は一つのセミナーしか担当しません。ただし、セミナーが終われば別のセミナーの講師になれます。)「セミナー」エンティティは、セミナーの開催が決まって初めて作成されるので、それまでは「社員」エンティティは存在していますが、「セミナー」エンティティが存在しないこともあります。しかし、「セミナー」が行われるときには、講師となる「社員」がいなければいけないので、「セミナー」エンティティから参照する「社員」エンティティの関係は必須となります。
データが発生する順番が決まっていない場合です。
例えば、基本的には受注生産ですが、あらかじめ製造しておくこともあるような商品のような場合です。基本的に商品は受注してから製造するので、受注があっても商品がありません。しかし、仕事が暇な時には受注に備えて、あらかじめ製造しておくこともあります。
どちらのデータが先に発生するかを業務内容から考慮して、一方が他方の外部キーを持つようにします。
リレーションシップでつながれた2つのエンティティの片方が1つ(例えば親、マスターエンティティ)に対して、反対側に複数のエンティティ(例えば子、ディテールエンティティ)が対応している状態です。
1対多のパターンは図のとおりで、ER図の中で最も多く使われています。
例えば、データの親と子が必ず存在する場合は (1)パターン、親が存在していても必ずしも子があるわけではない場合は (2)パターン(この場合は1側が先に発生している)、子供があっても親があるとは限らない場合は (3)パターン、必ずしも親があるとは限らず、子があるとは限らない(つまり、親子関係のデータもあるが、子のない親データもあるし、親のない子データもある)場合は (4)パターンというように考えます。
| 説明 | ||
|---|---|---|
| (1) | 両方向必須 親データに対応する複数の子データが存在する(理想) |
|
| (2) | 多側任意 親データに対応する複数の子データが存在するかもしれない |
|
| (3) | 1側任意 複数の子データに対応する親データが存在するかもしれない |
|
| (4) | 両方向任意 必ずしも親のある子データではなく、子がある親データでもない |
|
両方向必須です。ということは、リレーションシップのどちらかにデータが作成されたら、もう一方にもデータが作成されるということです。また、親データが削除されたら子データはすべて削除されますし、子データがすべて削除されたら親データも削除されることになります。つまり、同時発生・同時削除のパターンです。(ただし、子データの追加や一部削除はありえます。)
例えば、「受注」エンティティと「受注明細」エンティティがこれに当たります。受注したときに受注データが作成されます。そしてそれと同時に、どのような商品をいくつずつ受注したのかという受注明細データも作成されます。受注がキャンセルされた時には、受注データだけでなく、受注明細データもすべて削除されることになります。また、何らかの障害が発生し、受注明細データは作成できたが、受注データは作成できなかったという場合には、受注データの作成処理だけでなく、受注明細データの作成処理も取り消す(ROLLBACK)必要があります。
多側が任意の1対多です。実際のER図の中では最も多いパターンです。1対多の1側がマスタエンティティで、多側がディテールエンティティと呼ばれます。マスタエンティティにデータが登録されてから、ディテールエンティティの登録が行われるのが一般的です。したがって、マスタエンティティのデータ発生時に子は存在しないが、ディテールエンティティのデータが発生するときには参照できるマスタエンティティのデータが存在していなければいけません
例えば、 「商品」エンティティと「受注明細」エンティティがこれに当たります。1側の「商品」エンティティはマスタエンティティです。多側の「受注明細」エンティティはディテールエンティティで、商品が登録されていないうちから受注が発生することはありません。先に商品マスタにデータが登録されたあと、受注を受け付けることができます。
1側が任意の1対多です。1対多の中では最も少ないパターンです。通常1側はマスタエンティティですが、その1側のデータが発生するときに、多側のディテールエンティティのデータが存在していなければならず、逆に多側のデータが発生するときには、1側のデータが存在していなくてもよいというわけです。
このようなケースは考えにくく、1側任意のパターンは、少なくなりますが、例えば、「月次売上」エンティティと「日次売上」エンティティの関係がこれに当たります。「月次売上」は毎日の売り上げを集計した結果です。一つ以上の「日次売上」データから、「月次売上」が計算されます。先にデータが発生するのは、「日次売上」エンティティの方です。
ただし、1側の主キーを多側の外部キーとしては取り込めませんので、データベースに実装するときには、リレーションシップは定義しません。しかし、概念設計ではデータの関係を表現することが重要なので、リレーションシップを残したままにしておきます。このとき、「日次売上」エンティティの「売上日時」の一部(年月)は、「月次売上」エンティティ外部キーとして表現することができます。
両方向が任意の1対多です。必ずしも親のある子データばかりではなく、子がある親データだけでもありません。
リレーションシップは、場合によっては、単一のエンティティ内のエントリ間で関係が存在することがあります。このような場合、関係を「再帰」と呼びます。関係の両端は単一のエンティティに付加されます。
例えば、1人の社員は1人の他の社員にレポートするとします。つまり、プロジェクトのメンバーはプロジェクトのサブリーダに、サブリーダはプロジェクトリーダにレポートを提出するわけです。そして、1人の社員は0人以上の社員のレポートを受け取ります。つまり、プロジェクトサブリーダやプロジェクトリーダはレポートを受け取りますが、プロジェクトの一般のメンバーはレポートを受け取らないわけです。
リレーションシップでつながれた2つのエンティティが共に複数のエンティティで対応している状態です。
多対多のパターンは図のとおりです。
| 説明 | ||
|---|---|---|
| (1) | 両方向必須 子データに対応する複数の親データが存在し、また、親データに対応する複数の子データが存在する |
|
| (2) | 片方向任意 子データに対応する複数の親データが存在するが、親データに対応する子データが存在とはかぎらない。 |
|
| (3) | 両方向任意 必ずしも親のある子データではなく、子がある親データでもない |
|
例えば、商品は複数の顧客から注文されますし、顧客は複数の商品を注文をします。これが多対多の関係となります。しかし、この多対多のリレーションシップは管理すべきエンティティを見逃している可能性が高いことを示しています。再度分析して、見逃しているエンティティを見つければ、多対多のリレーションシップはなくなります。したがって、ここでそれぞれのパターンを考える必要はありません。
なお、 Oracleであればコレクション型、PostgreSQLであれば配列型といった特殊なデータ型を使用することによって実現できないこともありませんが、通常は分割します。
見逃しているエンティティを見つけるために、多対多のリレーションシップを分析する必要があります。多対多の分解については「3.1.2 リレーションシップを定義する (4) 多対多のリレーションシップの分解」で解説します。
属性とは、「エンティティが保有する情報で、エンティティが持つ性質、特性を表すもの」、「エンティティに完全に依存し、データ項目となるもの」です。
属性は、テーブルのカラムになります。よって、この属性の名前はとても重要です。あいまいさや誤解を受ける可能性を排除した名前にしなければいけません。たとえば、「商品」エンティティに「商品番号」、「商品名」、「価格」という属性が含まれていたとします。このときの「価格」とは何を意味するのかがあいまいなため、設計書を読んだ人ごとに「標準価格」、「販売価格」、「仕入価格」などと、それぞれのイメージで理解してしまう可能性があるからです。
通常、属性の名前は次の3つの要素に分類されます。
| 分類 | 概要 | 例 |
|---|---|---|
| 主要語 | データ項目の本質を表し、主に対象業務のエンティティ名と同じ | 商品、顧客、注文、部門、社員 |
| 分類語 | データ属性や種類、目的を表す | 番号、コード、名前、日付、数量、金額 |
| 修飾語 | 主要語と分類語だけではデータ項目が一意にならない場合に、データの内容を特定する | 当期開始(日付)、当月販売(金額)、初回生産(数量) |
先の「価格」という属性名は、分類語だけで表現した名前だったので、「標準」や「販売」という修飾語をつけて「標準商品価格」や「販売商品価格」とすれば、混乱なく理解することができることになります。
識別子とは、「データを一意に識別するための属性」です。
たとえば、「社員」エンティティにおいて、「社員番号」という属性があれば、これはレコードを一意に識別できるので識別子です。
しかし、識別子は、エンティティ内に一つしかないとは限りません。仮に「社員」エンティティにメールアドレスの属性が含まれていれば、これもレコードを一意に識別できるので識別子となり得ます。
つまり、「社員」エンティティには、「社員番号」と「メールアドレス」の2つの識別子が存在することになります。識別子は、主キーの候補となります。エンティティ内のいくつかの識別子の中から、1つの主キーが決まります。
また、複数の属性を組み合わせて識別子となる場合もあります。たとえば、「受注明細」エンティティには、「受注番号」、「明細番号」、「商品番号」 、「数量」の4つの属性があるとします。このとき、 「受注番号」、「明細番号」を組み合わせれば「受注明細」のレコードを識別できるので、この2つの属性を組み合わせて1つの識別子とすることができます。