@Bill Karwinは、SQL Entity-Attribute-Valueアンチパターンのソリューションを提案する際に、SQLアンチパターンの本で3つの継承モデルについて説明しています。これは簡単な概要です:
単一テーブル継承(別名、階層ごとの継承):
最初のオプションのように単一のテーブルを使用するのが、おそらく最も単純な設計です。おっしゃるように、サブタイプ固有の多くの属性にはNULL
を指定する必要があります これらの属性が適用されない行の値。このモデルでは、次のような1つのポリシーテーブルがあります。
+------+---------------------+----------+----------------+------------------+
| id | date_issued | type | vehicle_reg_no | property_address |
+------+---------------------+----------+----------------+------------------+
| 1 | 2010-08-20 12:00:00 | MOTOR | 01-A-04004 | NULL |
| 2 | 2010-08-20 13:00:00 | MOTOR | 02-B-01010 | NULL |
| 3 | 2010-08-20 14:00:00 | PROPERTY | NULL | Oxford Street |
| 4 | 2010-08-20 15:00:00 | MOTOR | 03-C-02020 | NULL |
+------+---------------------+----------+----------------+------------------+
\------ COMMON FIELDS -------/ \----- SUBTYPE SPECIFIC FIELDS -----/
デザインをシンプルに保つことはプラスですが、このアプローチの主な問題は次のとおりです。
-
新しいサブタイプを追加する場合は、これらの新しいオブジェクトを説明する属性に対応するようにテーブルを変更する必要があります。これは、多くのサブタイプがある場合、または定期的にサブタイプを追加する予定の場合、すぐに問題になる可能性があります。
-
どの属性がどのサブタイプに属するかを定義するメタデータがないため、データベースはどの属性が適用され、どの属性が適用されないかを強制できません。
-
NOT NULL
を強制することもできません 必須である必要があるサブタイプの属性について。これはアプリケーションで処理する必要がありますが、一般的には理想的ではありません。
具体的なテーブルの継承:
継承に取り組む別のアプローチは、サブタイプごとに新しいテーブルを作成し、各テーブルのすべての共通属性を繰り返すことです。例:
--// Table: policies_motor
+------+---------------------+----------------+
| id | date_issued | vehicle_reg_no |
+------+---------------------+----------------+
| 1 | 2010-08-20 12:00:00 | 01-A-04004 |
| 2 | 2010-08-20 13:00:00 | 02-B-01010 |
| 3 | 2010-08-20 15:00:00 | 03-C-02020 |
+------+---------------------+----------------+
--// Table: policies_property
+------+---------------------+------------------+
| id | date_issued | property_address |
+------+---------------------+------------------+
| 1 | 2010-08-20 14:00:00 | Oxford Street |
+------+---------------------+------------------+
この設計は、基本的に、単一テーブル方式で特定された問題を解決します。
-
必須属性を
NOT NULL
で適用できるようになりました 。 -
新しいサブタイプを追加するには、既存のテーブルに列を追加するのではなく、新しいテーブルを追加する必要があります。
-
vehicle_reg_no
などの特定のサブタイプに不適切な属性が設定されるリスクもありません。 プロパティポリシーのフィールド。 -
type
は必要ありません シングルテーブルメソッドのように属性。タイプはメタデータによって定義されます:テーブル名。
ただし、このモデルにはいくつかの欠点もあります。
-
共通の属性はサブタイプ固有の属性と混合されており、それらを識別する簡単な方法はありません。データベースも知りません。
-
テーブルを定義するときは、サブタイプテーブルごとに共通の属性を繰り返す必要があります。それは間違いなくドライではありません。
-
サブタイプに関係なくすべてのポリシーを検索することは困難になり、大量の
UNION
が必要になります。 s。
これは、タイプに関係なく、すべてのポリシーを照会する必要がある方法です。
SELECT date_issued, other_common_fields, 'MOTOR' AS type
FROM policies_motor
UNION ALL
SELECT date_issued, other_common_fields, 'PROPERTY' AS type
FROM policies_property;
新しいサブタイプを追加するには、上記のクエリを追加のUNION ALL
で変更する必要があることに注意してください。 サブタイプごとに。この操作を忘れると、アプリケーションにバグが発生しやすくなります。
クラステーブル継承(別名、タイプ継承ごとのテーブル):
これは、@Davidが他の回答で言及している解決策です。基本クラス用に単一のテーブルを作成します。これには、すべての共通属性が含まれます。次に、サブタイプごとに特定のテーブルを作成します。その主キーは、ベーステーブルへの外部キーとしても機能します。例:
CREATE TABLE policies (
policy_id int,
date_issued datetime,
-- // other common attributes ...
);
CREATE TABLE policy_motor (
policy_id int,
vehicle_reg_no varchar(20),
-- // other attributes specific to motor insurance ...
FOREIGN KEY (policy_id) REFERENCES policies (policy_id)
);
CREATE TABLE policy_property (
policy_id int,
property_address varchar(20),
-- // other attributes specific to property insurance ...
FOREIGN KEY (policy_id) REFERENCES policies (policy_id)
);
このソリューションは、他の2つの設計で特定された問題を解決します。
-
必須の属性は、
NOT NULL
で適用できます 。 -
新しいサブタイプを追加するには、既存のテーブルに列を追加するのではなく、新しいテーブルを追加する必要があります。
-
特定のサブタイプに不適切な属性が設定されるリスクはありません。
-
type
は必要ありません 属性。 -
これで、共通の属性がサブタイプ固有の属性と混合されなくなりました。
-
いよいよ乾いたままでいられます。テーブルを作成するときに、サブタイプテーブルごとに共通の属性を繰り返す必要はありません。
-
自動インクリメントの
id
の管理 ポリシーは、各サブタイプテーブルが個別に生成するのではなく、ベーステーブルで処理できるため、より簡単になります。 -
サブタイプに関係なくすべてのポリシーを検索することが非常に簡単になりました。
UNION
はありません s必要-SELECT * FROM policies
のみ 。
ほとんどの状況で、クラステーブルアプローチが最も適していると思います。
これら3つのモデルの名前は、MartinFowlerの著書Patternsof EnterpriseApplicationArchitectureに由来しています。