私が会社のデータベースをモデル化しようとしているこのケースを考えてみましょう:
Employees
、Managers
、Departments
。Employee
は1つのDepartment
でのみ機能しますが、Department
には多数のEmployees
が含まれている場合があります。Manager
は1つのDepartment
のみを管理でき、同様にDepartment
は1つのManager
のみを管理できます。Manager
は多数のEmployees
を監視しますが、Employee
は1つのManager
によってのみ監視されます。これをモデル化する方法は2つあります:
最初のソリューション:
Manager
エンティティはEmployee
エンティティから継承すると考えます。これは、マネージャに固有のデータ(ボーナスやステータスなど)を保持することを考慮しています。
Department
とEmployee
の関係は1:N
なので、Employee
テーブルのWorks
テーブルにDepartment Id
を外部キーとして配置します[$ var] _リレーション。
Department
とManager
の関係は1:1
なので、Manager
テーブルのManages
テーブルにDepartment Id
を外部キーとして配置します[$ var] _リレーション。
問題:Manager
とEmployee
の間の再帰的な関係をどのように表すことができますか?
2番目の解:
他のManager
にもEmployees
とBonus
が含まれている可能性があるため、Status
エンティティは不要であると考えます。 (実際には、両方のケースでモデル化する方法を確認するために、これら2つの属性を追加しました)
Department
とEmployee
の関係は1:N
なので、Employee
テーブルのWorks
テーブルにDepartment Id
を外部キーとして配置します[$ var] _リレーション。Employee
とManager
の関係は1:N
なので、Employee
テーブルのSupervises
テーブルにEmployee Id
を外部キーとして配置します[$ var] _リレーションとそれをManager Id
と呼びます。問題:Manager
とDepartment
の関係をどのように表すことができますか?
質問:
私はおそらく次のようなものに行くでしょう:
このモデルには次の特性があります。
注:DBMSが遅延制約をサポートしていない場合は、DEPARTMENT.MANAGER_IDをNULL可能にして、新しいデータの挿入を妨げるサイクルを解除する必要があります。
部門を一致させる必要がある場合は、DBMS固有の手法(トリガーや「特別な」制約など)を使用するか、DEPARTMENT_IDを従業員のPKに「伝播」します。この伝播により、最終的にマッチングが可能になります。
EMPLOYEE_IDはグローバルに一意である必要があるため、DEPARTMENT_IDと一緒に複合キーにとどまることはできません。したがって、これを代替キーにして、代わりにPKで代理EMPLOYEE_NOを使用します。
このモデルでは、ある部門を管理して別の部門で作業するマネージャーや、別の部門の従業員を監督する上司が存在しないようにします。
シンボルに慣れていない場合...
...「カテゴリ」を示します。このコンテキストでは、それをEMPLOYEEとMANAGER間の「1対0または1」の関係として簡単に解釈できます。
詳細については説明しませんが、従業員/マネージャー/部門のソリューションは、長期的には不快感の源(最初は)であり、次にデータベースの保守担当者にとって本当のPITA(後で)であることを保証します。 /またはそのインターフェースを開発する。だから私はあなたの2番目の提案を守ることをお勧めします。
マネージャー/部門の関係については、主にこの関係を表す2つの方法があります。どちらのソリューションでも、次のように実装できる「マネージャーが部署を管理する」関係に加えて、再帰的な「マネージャーが従業員を管理する」関係を維持することができます。
1-最初の/簡単な方法:部門テーブルにマネージャー/従業員IDを追加します。このフィールドはもちろん、従業員テーブルへの外部キーです
2-2番目/より複雑なソリューション:次のフィールドを持つ「マネージャー」テーブルを追加します。
Manager id (PK, surrogate)
Department id (FK)
Employee id (FK)
beginningDate
endingDate
管理履歴を保存する場所:誰から、どの部門に対して、いつから、いつまで
この場合、ビジネスルールを変換するためのロジック(トリガー、またはクライアント側の制御)を追加することを忘れないでください。たとえば、特定の期間と特定の部署には1人のマネージャーしか存在できず、部署はこれ以上滞在できません...マネージャーなしなど.
編集:
3-より豊かなソリューションは、私の2番目の提案を一般化したものであり、会社の全員のキャリアを追跡できるようにします。これは次のような「機能」テーブルで実行できます(ここでは「位置」テーブルと呼んでいるので、ここでは同じ用語を使用します:
Position id (PK, surrogate)
Department id (FK)
Employee id (FK)
Position Level (FK)
beginningDate
endingDate
「職位レベル」は、部門に存在する可能性のあるさまざまな職階を保持する別のテーブルにつながりますが、その1つはもちろん「マネージャー」の職位です。
この提案は、人事データベースとソフトウェアで使用されているものにより近く、そのような複雑なソリューションは必要ないかもしれません。ただし、人間を複数のテーブルに分割することは常に間違いであることを覚えておいてください。
編集:あなたのコメントに従って...
わかりやすくするために、フィールド名を調整することをお勧めします。次のフィールドを用意することをお勧めします。
Tbl_Employee.id_EmployeeManager
そして
Tbl_Department.id_DepartmentManager
これにより、私たち(または開発者)は、id_EmployeeManagerが個人間の再帰的な関係に参加し、id_DepartmentManagerが個人と部門間の関係に参加することをすぐに理解できます。
あなたの質問に戻って、私によれば、あなたは次のリンクを作成すべきではありません:
Tbl_Department.id_DepartmentManager -> Tbl_Employee.id_EmployeeManager
そうすることで、誰かが部長になれないことを意味しますunless彼はすでに従業員を管理しています。従業員が1人の部門についてはどうですか?従業員がまだ割り当てられていない、新しく作成された部門のマネージャーという名前の人はどうですか?それは動作しません。正しいリンクは次のとおりです。
Tbl_Department.id_DepartmentManager -> Tbl_Employee.id_Employee
もちろん、たとえば、「部署を管理する従業員はマネージャーのみになることができる」(id_Employeeはid_EmployeeManagerとしてどこかに存在する)、または「部署を管理する従業員はマネージャーを持つことができない(この従業員のid_EmployeeManagerはnullである)」というビジネスルールを追加できます。 ...)しかし、これらはビジネスルールにすぎません。データモデルは、基本的なルールが守られている限り、つまり部署が従業員によって管理されている限り、すべてのルールを受け入れることができます。
私の意見:
従業員とマネージャーの両方の情報を追加するテーブルパーソン、マネージャーも人間ですよね? :)、そしてあなたはマネージャーのIDにリンクするmanagerIdフィールドを持っています。
部門情報を含むテーブル部門
また、従業員が複数の部門に所属できる場合は、それらを関連付けるためにテーブルemployee_departmentを作成します。従業員が所属できる部門が1つだけであり、関係の詳細が必要ない場合は、EmployeeテーブルにdepartmentIDフィールドを追加します。
私はこれが最良の解決策だと思います:
マネージャーは、部門を管理する従業員です。次のフローで取得できる再帰関係:
従業員は部門を持っています部門はマネージャーとして従業員を持っています
たぶん、ロールを定義するために従業員テーブルにEmployeeType列を与えるのに便利です。
2つ目のデザインにこだわって疑似関係を作ってみませんか?
従業員エンティティと部門エンティティ間の関係をリンクするために、従業員エンティティにdepartment_id
列があることを想定しています。マネージャー階層(マネージャーのマネージャー)がないと想定できる場合は、2つのテーブル間に擬似関係を適用できます。ここで、マネージャーのDepartment_ID
(Manager_ID
はNull)は部門を表します管理する。
これを明確に文書化している限り、Departmentエンティティを参照するEmployeeエンティティにFK列(department_id
)が既にあるので、スペース効率の良いアプローチになると思います。