タイトルがわかりずらくてすみません。
次のようなデータ モデルが必要です。
ご覧のとおり、セットはユーザーまたは学校の両方に属することができます。私の問題: ユーザーまたは学校のいずれかに属することのみを許可する必要があります。しかし、両方を同時に行うことは決してありません。
どうすればこの問題を解決できますか?
タイトルがわかりずらくてすみません。
次のようなデータ モデルが必要です。
ご覧のとおり、セットはユーザーまたは学校の両方に属することができます。私の問題: ユーザーまたは学校のいずれかに属することのみを許可する必要があります。しかし、両方を同時に行うことは決してありません。
どうすればこの問題を解決できますか?
現在の設計は排他アークと呼ばれ、sets
テーブルに2つの外部キーがあり、そのうちの1つだけがnull以外である必要があります。特定の外部キーは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
これは、オブジェクト指向モデリングのインターフェースに類似していると考えることができます。
interface SetOwner { ... }
class User implements SetOwner { ... }
class School implements SetOwner { ... }
class Set {
SetOwner owner;
}
コメントを再確認してください。
つまり、SetOwnerテーブルにはUserIDとSchoolIDの両方が含まれていますね。つまり、ユーザーと学校で同じIDを持つことは許可されないということです。どうすればこれを実施できますか?
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値が学校とユーザーの両方に使用されることはありません。
セットの所有者タイプを取得したい場合、SetOwnerテーブルにownerType属性が必要ですか?
あなたは確かにこれを行うことができます。実際、ユーザーと学校の両方に共通する他の列が存在する可能性があり、これらの列をスーパーテーブルのSetOwnersに配置できます。これは、MartinFowlerのクラステーブル継承パターンに入ります。
また、学校またはユーザーの名前(どちらのタイプでも)を取得したい場合、1つのクエリでこれを実行できますか、それとも2つのクエリ(最初にタイプを取得し、次に名前を取得する)が必要ですか?
参加する必要があります。特定のセットからクエリを実行していて、それが(学校ではなく)ユーザーに属していることがわかっている場合は、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のいずれかのテーブルと一致する必要がありますが、両方と一致する必要はありません。
警告があります: Set がデータモデルで何であるかは完全には明らかではありません。
あなたのデータモデルについて質問しています。
User -> Sets と School -> Sets が同じテーブルを指す必要があるのはなぜですか。それらが本当に独立したデータのセットである場合、それは正規化されたものではありません。追跡する列にいくつかの類似点があるからといって、同じテーブルに格納する必要があるわけではありません。それらは論理的に同じものですか?
スクール セット用とユーザー セット用に別々のテーブルを作成するだけです。これにより、Sets テーブルの null リレーションシップをチェックして、それが実際に UserSet であるか SchoolSet であるかを確認する必要がないため、逆クエリも簡単になります。
MySQL には (どのエンジンにも) CHECK 制約がありますが、強制しないため、このビジネス ルールを強制するにはトリガーを使用する必要があります。