あなたが与えたビジネスルールの外で
- 各親には少なくとも 1 人の子が必要です。
- 各親にはお気に入りの子供が 1 人必要です。
- 各親は、最もお気に入りでない子を 1 人持つことができます
あなたのソリューション
Parent table:
parentId (PK)
favouriteChildId NOT NULL (FK)
leastFavouriteChildId NULL (FK)
Child table:
childId (PK)
parentId (FK)
2 と 3 を満たします。ただし、1 も満たします (favouriteChildId NOT NULL では、子のない親レコードを作成できないため)。
あなたはすでに上記を持っているので、あなたにとっての本当の質問は、子テーブルのparentIdをNOT NULLにする方法だと思います。
通常、次のようなことができるようにSQLに規定があります
BEGIN TRANS
INSERT INTO TABLE1 (FK not checked yet)
INSERT INTO TABLE2 (FK not checked yet)
COMMIT (All integrity checked)
その場合、「循環参照」は問題になりません ( DEFERREDを参照) 。
Mysql ではサポートされていないため、次のオプションがあります。
トリガー:
親レコードを挿入する時点で、お気に入りの子がすでにわかっていると想定できます。その場合、親テーブルに挿入する前に実行されるトリガーを設定できます。
- お気に入りの子を子テーブルに挿入し、その ID を取得します
- 子の ID を持つ親レコードを挿入します
注: 問題は、この方法で基準を正式に満たすことができることですが、最初に子レコードを挿入するには、親で追加の列を使用して、トリガーが子テーブルの他のフィールドについて認識できるようにするか、空白のレコードを挿入する必要があります (どちらの場合もデザインはきれいではありません)
セキュリティによる整合性
上記は、親テーブル レベルで追加のフィールドを必要とせずに、ストアド プロシージャとして実装できます。ただし、通常、ストアド プロシージャはバイパスされる可能性があるため、実際の整合性ルールとしての資格はありません。
ストアド プロシージャで達成されたものを整合性ルールとして認定する一般的な方法があります。それは、これらのテーブルに対するすべての通常のユーザー (およびアプリケーション) の書き込み権限を削除し、ストアド プロシージャを介してのみデータを変更できるようにすることです。
EDIT:トリガーに関しては、トリガーを使用してルールを実装する方法もあります。つまり、レコードを個別に挿入する必要があり、ビジネスルールを破るデータを一度に持つ必要があることを受け入れることです。
その場合、親レコードの STATUS 属性 (例: COMPLETE と INCOMPLETE) を設定し、favouriteChildId を NULL 可能な FK にすることができますが、ステータスを COMPLETE に更新するときに、整合性が尊重されていることをトリガー チェックすることができます。
これには追加の列が必要ですが、物事を非常にきれいにすることができます(実際には、このテーブルに COMPLETE のレコードのみを公開するビューを作成して、効果的に FK NOT NULL を持つテーブルのように見せることができます)。