TASKS テーブルで FRUIT_TYPE を特定する必要がある理由がよくわかりません。一見すると、これは貧弱な (非正規化された) データ モデルです。
私の経験では、この種のデータをモデル化する最良の方法は、一般的なもの (例では FRUIT) のスーパータイプと詳細 (APPLE、GRAPE、BANANA) のサブタイプを使用することです。これにより、各インスタンスの特定の属性を記録しながら、共通の属性を 1 か所に保存できます。
スーパータイプのテーブルは次のとおりです。
create table fruits
(fruit_id number not null
, fruit_type varchar2(10) not null
, constraint fruit_pk primary key (fruit_id)
, constraint fruit_uk unique (fruit_id, fruit_type)
, constraint fruit_ck check (fruit_type in ('GRAPE', 'APPLE', 'BANANA'))
)
/
FRUITS には、主キーと複合一意キーがあります。複合キーは面倒なので、外部キー制約で使用する主キーが必要です。そうでない場合を除いて、これらのサブタイプ テーブルの状況です。サブタイプの FRUIT_TYPE の値を制約することで、GRAPES テーブル内のレコードがタイプ「GRAPE」などの FRUITS レコードにマップされることを保証できるため、ここでは一意のキーを参照として使用します。
create table grapes
(fruit_id number not null
, fruit_type varchar2(10) not null default 'GRAPE'
, seedless_yn not null char(1) default 'Y'
, colour varchar2(5) not null
, constraint grape_pk primary key (fruit_id)
, constraint grape_ck check (fruit_type = 'GRAPE')
, constraint grape_fruit_fk foreign key (fruit_id, fruit_type)
references fruit (fruit_id, fruit_type)
, constraint grape_flg_ck check (seedless_yn in ('Y', 'N'))
)
/
create table apples
(fruit_id number not null
, fruit_type varchar2(10) not null
, apple_type varchar2(10) not null default 'APPLE'
, constraint apple_pk primary key (fruit_id)
, constraint apple_ck check (fruit_type = 'APPLE')
, constraint apple_fruit_fk foreign key (fruit_id, fruit_type)
references fruit (fruit_id, fruit_type)
, constraint apple_type_ck check (apple_type in ('EATING', 'COOKING', 'CIDER'))
)
/
create table bananas
(fruit_id number not null
, fruit_type varchar2(10) not null default 'BANANA'
, constraint banana_pk primary key (fruit_id)
, constraint banana_ck check (fruit_type = 'BANANA')
, constraint banana_fruit_fk foreign key (fruit_id, fruit_type)
references fruit (fruit_id, fruit_type)
)
/
11g では、FRUIT_TYPE をサブタイプの仮想列にして、チェック制約をなくすことができます。
そこで、タスクの種類 (「皮をむく」、「冷蔵する」、「食べる」など) のテーブルが必要です。
create table task_types
(task_code varchar2(4) not null
, task_descr varchar2(40) not null
, constraint task_type_pk primary key (task_code)
)
/
実際の TASKS テーブルは、FRUITS と TASK_TYPES の単純な共通部分です。
create table tasks
(task_code varchar2(4) not null
, fruit_id number not null
, constraint task_pk primary key (task_code, fruit_id)
, constraint task_task_fk ask foreign key (task_code)
references task_types (task_code)
, constraint task_fruit_fk foreign key (fruit_id)
references fruit (fruit_id)
/
これでニーズが満たされない場合は、質問を編集して詳細情報を含めてください。
「…果物ごとに異なるタスクが必要な場合は…」
はい、それがOPの投稿されたデザインの根底にある動機であるかどうか疑問に思いました. しかし、通常、ワークフローはそれよりもはるかに困難です。すべての果物に適用されるタスクもあれば、束になっている果物にのみ適用されるタスクもあれば、バナナにのみ関連するタスクもあります。
「私たちの実際のロジックでは、「成果」は、共通性がほとんどないまったく異なるテーブルです。顧客、従業員、会議、部屋、建物、資産タグなどを考えてください。ステップのリストは自由形式であると想定されており、ユーザーがこれらのいずれかに対するアクションを指定します。」
したがって、既存のテーブルがたくさんあります。これらのテーブルのレコードをタスクにフリーホイール スタイルで割り当てることができるようにする必要がありますが、タスクを所有する特定のレコードの識別を保証できるようにする必要があります。
タスク内のアクターの ID を保持するための一般的なテーブルが必要だと思いますが、何らかの方法でそれを他のテーブルにリンクする必要があります。これが私がそれにアプローチする方法です:
既存のテーブルの例:
create table customers
(cust_id number not null
, cname varchar2(100) not null
, constraint cust_pk primary key (fruit_id)
)
/
create table employees
(emp_no number not null
, ename varchar2(30) not null
, constraint emp_pk primary key (fruit_id)
)
/
アクターを保持する汎用テーブル:
create table actors
(actor_id number not null
, constraint actor_pk primary key (actor_id)
)
/
ここで、既存のテーブルを新しいテーブルに関連付ける交差テーブルが必要です。
create table cust_actors
(cust_id number not null
, actor_id number not null
, constraint cust_actor_pk primary key (cust_id, actor_id)
, constraint cust_actor_cust_fk foreign key (cust_id)
references customers (cust_id)
, constraint cust_actor_actor_fk foreign key (actor_id)
references actors (actor_id)
)
/
create table emp_actors
(emp_no number not null
, actor_id number not null
, constraint emp_actor_pk primary key (emp_no, actor_id)
, constraint emp_actor_emp_fk foreign key (emp_no)
references eployees (emp_no)
, constraint cust_actor_actor_fk foreign key (actor_id)
references actors (actor_id)
)
/
以前に行ったことを考えると、TASKS テーブルはかなり驚くべきものではありません。
create table tasks
(task_code varchar2(4) not null
, actor_id number not null
, constraint task_pk primary key (task_code, actor_id)
, constraint task_task_fk ask foreign key (task_code)
references task_types (task_code)
, constraint task_actor_fk foreign key (actor_id)
references actors (actor_id)
/
これらの交差テーブルはすべてオーバーヘッドが大きいように見えることに同意しますが、外部キー制約を強制する他の方法はありません。追加の問題は、CUSTOMERS でレコードを作成するたびに ACTORS および CUSTOMER_ACTORS レコードを作成することです。削除についても同様です。唯一の良いニュースは、必要なすべてのコードを生成できることです。
このソリューションは、100 個のオプションの外部キーを持つテーブルよりも優れていますか? そうではないかもしれませんが、それは好みの問題です。しかし、外部キーがまったくないよりはましです。データベースの実践に普遍的な真実があるとすれば、それは次のとおりです。リレーショナル整合性を強制するためにアプリケーションコードに依存しているデータベースは、間違った親を参照している、または親をまったく参照していない子でいっぱいのデータベースです。