このために 2 つのテーブルが必要な理由がいくつかわかります。
- 実際の従業員は名前、部署などを持っている必要がありますが、予測従業員のみがこれらの属性を持つことができます
- 実際の従業員のみが持つことができる責任があるため、それらを個別に参照できるようにする必要があります
しかし同時に、2 つのテーブル間で ID が衝突しないようにする必要があります。これは、(できれば) 従業員の予測が実際の従業員になるためです。
これを行う方法は、スーパータイプ/サブタイプ構造を実装することです。つまり、1 つの主キーを保証する EMPLOYEES テーブルと、実際の従業員と予測従業員用の 2 つの従属テーブルがあります。特定の従業員が 1 つのサブテーブルにのみ表示されるようにするため、type 列の使用は非常に重要です。
create table employees
( emp_id number not null
, emp_type varchar2(8) not null
, constraint emp_pk primary key (emp_id)
, constraint emp_uk unique (emp_id, emp_type)
, constraint emp_type_ck check (emp_type in ('FORECAST', 'ACTUAL'));
create table actual_employees
( emp_id number not null
, emp_type varchar2(8) not null
, name varchar2(30) not null
, deptno number(2,0) not null
, sal number(7,2) not null
, hiredate date not null
, constraint actemp_pk primary key (emp_id)
, constraint actemp_type_ck check (emp_type = 'ACTUAL')
, constraint actemp_emp_fk foreign key (emp_id, emp_type)
references emp (emp_id, emp_type)
deferrable initially deferred ;
create table forecast_employees
( emp_id number not null
, emp_type varchar2(8) not null
, name varchar2(30)
, deptno number(2,0)
, sal number(7,2)
, predicted_joining_date date
, constraint foremp_pk primary key (emp_id)
, constraint foremp_type_ck check (emp_type = 'FORECAST')
, constraint foremp_emp_fk foreign key (emp_id, emp_type)
references emp (emp_id, emp_type)
deferrable initially deferred ;
そのため、キーが少し奇妙に見えるかもしれません。親テーブルには、主キーと複合一意キーの両方があります。主キーは、EMP_ID の単一インスタンスを保証します。一意のキーにより、EMP_ID と EMP_TYPE の両方を参照する子テーブルに外部キーを作成できます。子 t のチェック制約と組み合わせる これは、親テーブルの主キーではなく、親テーブルの一意のキーを参照するためです。この取り決めにより、従業員は FORECAST_EMPLOYEES または ACTUAL_EMPLOYEES のいずれかに所属できますが、両方に所属することはできません。
外部キーは、予測従業員を実際の従業員に変換できるように遅延可能です。これには、次の 3 つのアクティビティが必要です。
- FORECAST_EMPLOYEES からのレコードの削除
- ACTUAL_EMPLOYEES へのレコードの挿入
- EMPLOYEES のEMP_TYPE ( EMP_ID ではない) を変更します。
アクション 2 と 3 の同期は、遅延制約を使用すると簡単です。
また、EMPLOYEES を参照する他の外部キー制約では、一意キーではなく主キーを使用する必要があることに注意してください。リレーションシップが従業員のタイプを気にする場合は、代わりに子テーブルにリンクする必要があります。
「ちょっと頭が痛い」
データモデリングの世界へようこそ。それは一つの大きな頭痛の種です。乱雑な現実をクリーンなデータ モデルに当てはめようとするのは難しいため、それを正しく行うには明確な要件が必要であり、賢明な妥協ができるように最も重要なことを理解する必要があります。
他の質問に基づいて、スーパータイプ/サブタイプのアプローチを提案しました。これは、実際の従業員と概念上の従業員という 2 つのデータセットを処理する最良の方法と思われるためです。この 2 つのグループは、異なる扱いを受ける必要があると思います。たとえば、私はマネージャーが実際の従業員であることを主張します。これは、ACTUAL_EMPLOYEES に対する整合性制約で簡単に実行できますが、両方のタイプの従業員を含む単一のテーブルで達成するのははるかに困難です。
確かに、テーブルが 2 つあるということは、それらの構造の同期に関して、より多くの作業が発生する可能性があることを意味します。だから何?1 つよりも 2 つの ALTER TABLE ステートメントを作成する方がほとんど作業がかからないため、これはほとんど簡単です。さらに、新しい列が実際の従業員にのみ適用され、従業員の予測には意味がない可能性は十分にあります (例: EARNED_COMMISSION、LAST_REVIEW_RATING)。その観点から、個別のテーブルを使用すると、データ モデルがより正確になります。
Ollie が指摘するように、従属テーブルを複製しなければならないことに関しては、それは誤解です。実際の従業員に関係なくすべての従業員に適用されるテーブルは、その子ではなく EMPLOYEES テーブルを参照する必要があります。
最後に、1 つよりも 2 つのテーブルの方が履歴データの維持が難しい理由がわかりません。ほとんどのジャーナリング コードは、データ ディクショナリから完全に生成する必要があります。
"Employee テーブルと Employee_forecast テーブルがある場合 ..."
次の 3 つのテーブルがあります。
- EMPLOYEES - 一意の EMP_ID を保証するマスター テーブル
- ACTUAL_EMPLOYEES - 会社で働く人々の子テーブル
- FORECAST_EMPLOYEES - あなたの会社に採用したい人の子テーブル
「...製品または活動の両方が 1 つの製品/活動テーブルに保存されますか?」
あなたが提供したわずかな詳細から、あなたのビジネス ロジックについて推測していることに注意してください。
現在、あなたの会社でまだ働いていない人は、関連する活動を行うべきではないように思えます。このシナリオでは、ACTUAL_EMPLOYEES の子である EMPLOYEE_ACTIVITIES という 1 つのテーブルを作成します。
しかし、あなたは存在しない人々のために本当に活動をしているのかもしれません。ここに選択肢があります。1 つまたは 2 つのテーブルでしょうか。1 つのテーブルの設計には、マスター EMPLOYEES テーブルの子として EMPLOYEE_TASKS があります。2 つのテーブルの設計には、それぞれ ACTUAL_EMPLOYEES および FORECAST_EMPLOYEES テーブルの子として ACTUAL_EMPLOYEE_TASKS および FORECAST_EMPLOYEE_TASKS があります。
どの設計が正しいかは、タスクの割り当てに関する規則を適用する必要があるかどうかによって異なります。たとえば、あなたの会社には、実在の人物だけが新しいスタッフを雇うことができるというルールがあるとします。したがって、採用タスクのみを ACTUAL_EMPLOYEES に割り当てることができるモデルがあると便利です。
「この設計では、月ごとの予測は考慮されていません」
さて、2 つのテーブルに日付列を追加しました。これにより、必要なレポートを実行できます。