1

私はこの問題に直面しています:

親テーブルと子テーブルがあり、1人の親が複数の子を持つことができます。標準的なストーリーです。

これらは制約です:

  • 各親には少なくとも1人の子供が必要です。
  • 各親には1人のお気に入りの子供が必要です。
  • 各親は1人の最も嫌いな子供を持つことができます

これをSQLで設計するにはどうすればよいですか?

循環関係があるため、標準の親子テーブルを使用できるかどうかはわかりません。

Parent table:
parentId
favouriteChildId NOT NULL
leastFavouriteChildId NULL

Child table:
childId
parentId

ブリッジテーブルの使用を考えていましたが、これらの制約をモデル化する方法がわかりません。


編集:明確にするために、ここに問題のコンテキストの一部があります:

Priceテーブル(子)とPriceGroupテーブル(親)があります。

PriceGroupには複数の価格があり、1つの必須のmainPrice(favouriteChild)と1つのofficialPrice(leastFavouriteChild)を持つことができます。

以下は問題とは関係ありませんが、コンテキストに光を当てます。価格は参照する製品に従ってグループ化され、1つの製品は複数の価格を持つことができます。これらは価格グループにグループ化され、各グループは参照する必要があります。メイン価格、および公式価格(ある場合)。

4

3 に答える 3

3

あなたが与えたビジネスルールの外で

  1. 各親には少なくとも 1 人の子が必要です。
  2. 各親にはお気に入りの子供が 1 人必要です。
  3. 各親は、最もお気に入りでない子を 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 を持つテーブルのように見せることができます)。

于 2011-05-16T10:48:54.697 に答える
2

他の制約を(ある程度)モデル化できます。

Parent Table
parentId (PK)

Child table:
childId  (PK)
parentId (FK)

Is Favorite table:
childID (PK)(FK)

Is Least Favourite table:
ChildID (PK)(FK)

行は常にIsFavoriteChildに挿入されます。1つは、最もお気に入りの子がない場合にのみIs Least Favoriteに挿入されます。挿入、更新、削除は、ビューのトリガーによって実行されます。テーブルの左結合による選択。

これは、Favorite Childリレーションの必須の性質を処理しません。これは、挿入/更新/削除トリガーによって処理する必要があります。

于 2011-05-16T10:28:05.770 に答える
0

深さが 1 レベルだけの場合:

Parents ( ParentID, Title, etc )
Children ( ChildID, ParentID, Title, etc )

EveryChildは常に正確に 1Parentを持ち、Parents常に を持っている必要があります>= 0 Children。(それを回避する方法はありません。)

複数の (不明な) レベルが深い場合:

Items ( ItemID, ParentItemID NULL, Title, etc )

非常に簡単です:Items.ParentItemID = Items.ItemID

edit
複数の (不明な) レベルが必要な場合、クエリは複数になり、合計結果をキャッシュすることは非常に良い考えです。(すべての子には、直接の子などを取得するための別のクエリがあります。)

于 2011-05-16T10:08:00.643 に答える