現在のデザインは排他的アークと呼ばれます ここで、sets
テーブルには2つの外部キーがあり、そのうちの1つだけがnull以外である必要があります。特定の外部キーは1つのターゲットテーブルしか参照できないため、これはポリモーフィックアソシエーションを実装する1つの方法です。
もう1つの解決策は、両方のusers
が共通の「スーパーテーブル」を作成することです。 およびschools
参照し、それをsets
の親として使用します 。
create table set_owner
create table users
PK is also FK --> set_owner
create table schools
PK is also FK --> set_owner
create table sets
FK --> set_owner
これは、インターフェースに類似していると考えることができます。 OOモデリングの場合:
interface SetOwner { ... }
class User implements SetOwner { ... }
class School implements SetOwner { ... }
class Set {
SetOwner owner;
}
コメントを再確認してください:
SetOwnersテーブルにid値を生成させます。ユーザーまたは学校に挿入する前に、SetOwnersに挿入する必要があります。したがって、ユーザーと学校のIDをではないようにします。 自動インクリメント; SetOwnersによって生成された値を使用するだけです:
INSERT INTO SetOwners DEFAULT VALUES; -- generates an id
INSERT INTO Schools (id, name, location) VALUES (LAST_INSERT_ID(), 'name', 'location');
このように、特定のID値が学校とユーザーの両方に使用されることはありません。
あなたは確かにこれを行うことができます。実際、ユーザーと学校の両方に共通する他の列が存在する可能性があり、これらの列をスーパーテーブルのSetOwnersに配置できます。これは、MartinFowlerの
参加する必要があります。特定のセットからクエリを実行していて、それが(学校ではなく)ユーザーに属していることがわかっている場合は、SetOwnersへの参加をスキップして、ユーザーに直接参加できます。結合は必ずしも外部キーによるものである必要はありません。
SELECT u.name FROM Sets s JOIN Users u ON s.SetOwner_id = u.id WHERE ...
特定のセットがユーザーに属しているのか学校に属しているのかわからない場合は、両方に外部結合を行う必要があります。
SELECT COALESCE(u.name, sc.name) AS name
FROM Sets s
LEFT OUTER JOIN Users u ON s.SetOwner_id = u.id
LEFT OUTER JOIN Schools sc ON s.SetOwner_id = sc.id
WHERE ...
SetOwner_idは、UsersまたはSchoolsのいずれかのテーブルと一致する必要がありますが、両方と一致する必要はありません。