6

モデル「A」のテーブルを考えると、複数の子モデル「B」を持つことができ、そのうちの「B」には1つ以上の子モデル「C」があります..これは簡単に聞こえますが、「A」ごとに強制する必要があります'、任意の 'B' は 'C' の一意のコレクションを持つ必要があります..たとえば、C は、同じ親 'A' の一部である 2 つの 'B' の子になることはできません.. ただし、'C' は子になることができます各 'B' の親 'A' が異なる場合、複数の 'B' の

それは理にかなっていますか、それともシナリオの難読化を解除する必要がありますか? 事前に乾杯!

このポリシーがアプリケーションに適用されることはわかっていますが、データベースが無効な状態になることを不可能にしたくないことに注意してください。

編集:こんにちは、素晴らしいフィードバックです。まず、知識を共有してくださった皆さんに感謝しなければなりません。

状況を明確にするために、シナリオを説明しますが、ここにいくつかの注意事項があります。

'A' には 0 個以上の 'B' があり、'B' は暗黙的に 'A' に関連付けられているため、常に 1 つの 'A' の子になります。「C」は、データベース内の多くの「B」やその他の要素に関連付けられているルート エンティティのようなものです。


これが本当の話です:

これは、多くのブリーフ (A) と多くのメンバー (C) を含む Web サイトです。ブリーフには多くの提出物 (B) を含めることができます。提出物には、常に 1 つ以上の関連メンバーが含まれます。アイデアは、提出物は実際にはコラボレーションである可能性があり、各メンバーは他のメンバーよりも多くの「力」を持っていませんが、メンバーがどのように協力するかのポリシーを検証するための異なるシステムが配置されるというものです.

したがって、ブリーフごとに、メンバーは 1 つの提出のみを提出でき、提出には多くのメンバー (共同作業者) を含めることができます。

お役に立てば幸いですが、すでに十分なご支援をいただいていると思います。

スティーブ。

4

5 に答える 5

3

ここであなたの関係モデルをキャプチャしたと思います。そうでない場合、私は難読化しないことに投票します:

  • A [{AID}、...]
  • B [{BID}、AID、...]
  • C [{CID}、...]
  • B_C_Link [{BID、CID}、AID]
    • (AID、CID)に関する追加の一意のインデックス

表記では、{}主キーインジケーターを使用します。したがって、(BにAIDを配置することによって)複数のBを持つことができるので、Bは(多対多のテーブルB_C_Linkを使用することによって)Cを持つことができ、複数のCは(多対多にAIDを追加することによって)同じAに属することはできません。多対多のテーブルと強制(AID、CID)の一意性。

于 2009-03-17T12:41:59.467 に答える
3

SQL 標準アサーションが必要だと思いますが、これは (残念ながら) 実際の DBMS ではほとんど実装されていません。

すべての回答は、TableA、TableB、および TableC と呼ばれる 3 つのプライマリ テーブルがあり、それぞれに独自の ID 列が含まれていることに同意しています。

TableA (A_ID PRIMARY KEY, ...)
TableB (B_ID PRIMARY KEY, ...)
TableC (C_ID PRIMARY KEY, ...)

単一の B 値が複数の A 親エントリを持つことができるかどうかは、問題の説明から明らかではありません。単一の C が複数の B 親エントリを持つことができることは明らかです。B が 1 つの A に関連付けられている場合、TableB の設計は次のように変更できます。

TableB (B_ID, ..., A_ID REFERENCES TableA)

B をいくつかの異なる A に関連付けることができる場合、接続は結合テーブルによって最もよく表されます。

A_and_B (A_ID REFERENCES TableA,
         B_ID REFERENCES TableB,
         PRIMARY KEY (A_ID, B_ID)
        )

また、B に関連付けられた C が、B に関連付けられたすべての A に対して同じでなければならないのか、または異なる A が同じ B を参照できるのか、および A1 の B に関連付けられた C のセットが説明から明らかではないA2 の B に関連付けられている C のセットとは異なる場合があります。(もちろん、1 つの B が 1 つの A にしか関連付けられない場合、この問題は意味がありません。)

この回答の目的のために、任意の B が単一の A に関連付けられていると仮定するので、TableB の構造には A_ID が外部キーとして含まれています。単一の C を複数の B に関連付けることができるため、関連する構造は新しい結合テーブルです。

B_and_C (B_ID REFERENCES TableB,
         C_ID REFERENCES TableC,
         PRIMARY KEY (B_ID, C_ID)
        )

アサーションを単純化すると (延期可能性と即時性に関するルールを省略して)、次のようになります。

CREATE ASSERTION assertion_name CHECK ( <search_condition> )

したがって、一連の設計上の決定事項が得られたら、データを検証するためのアサーションを作成できます。テーブル TableA、TableB (外部キー A_ID を使用)、TableC、および B_and_C が与えられた場合、完全な A 全体での特定の C_ID の出現回数が 1 であることが要件です。

CREATE ASSERTION only_one_instance_of_c_per_a CHECK
(
     NOT EXISTS (
         SELECT A_ID, COUNT(C_ID)
             FROM TableB JOIN B_and_C USING (C_ID)
             GROUP BY A_ID
             HAVING COUNT(C_ID) > 1
     )
)

[修正: これはより正確だと思います:

CREATE ASSERTION only_one_instance_of_c_per_a CHECK
(
     NOT EXISTS (
         SELECT A_ID, C_ID, COUNT(*)
             FROM TableB JOIN B_and_C USING (C_ID)
             GROUP BY A_ID, C_ID
             HAVING COUNT(*) > 1
     )
)

]

結合条件のセットは、テーブルの接続方法に関する他のルールによって異なりますが、全体的な制約構造は同じままです。特定の A_ID に対して特定の C_ID への参照が複数存在してはなりません。


以下のコメントで、meandmycode のメモ:

自分のデザインに欠陥があるような気がします。私の現実世界の論理は、「B」には常に少なくとも 1 つの子「C」があるというものです。'B' がその子をアタッチする前に存在しなければならないことを考えると、これは意味がありません。現在、データベースでは、少なくとも 1 つの「C」を持たずに「B」を「A」に関連付けることができます。そのため、「B」を修正して、その子を参照するフィールドを持つようにします。追加の「C」の子コレクションを持つだけでなく、「B」で指定されたプライマリ「C」も含めることができるコレクションがありますが、これは間違っています。

「1 つ以上の子」ルールとゼロ以上のルールを推論するデータベース パターンはありますか?

モデルに問題があると思います。新しく作成された B を参照する C が既に存在している必要がある場合、特に C が既存の B のみを参照する必要がある場合、B を作成するのは困難です。「鶏と卵」という言葉が思い浮かびます。したがって、通常、このようなコンテキストでは、B が 0 個以上の C を持つことを許可します。

TableB に A_ID 外部キーがあるかどうか、または A_and_B のようなリンク テーブルがあるかどうかはまだ規定していません。外部キーがある場合、参照先の A を作成するまで、おそらく B を作成できません。

テーブル B に 1 つの C ID を含めることは良い考えではないと思います。非対称処理 (より難しい SQL) になります。また、その 1 つの C を削除する必要がある場合は、現在あるテーブルから他の C 参照の 1 つが削除されるように更新してから、B レコードの値を更新する必要があることも意味します。それについて礼儀正しくするために、それは面倒です。

さまざまな回答に示されている行に沿って、見ている実際のテーブル構造を定義するために質問を修正する必要があると思います。3 つのドットを使用して、他の関係のない列を表すことができます。私が提案したアサーションは、おそらくある種のトリガーとして実装する必要があります。これは、DBMS 固有の表記法になります。


ブリーフ (A)、サブミッション (B)、およびメンバー (C) の修正された説明から、1 つのサブミッションが 1 つのブリーフのみに適用されることは明らかです。そのため、サブミッションは、サブミッションであるブリーフを識別する単純な外部キーを持つことができます。為に。また、メンバーは、特定のブリーフの 1 つの提出物に対してのみ共同作業できます。提出物とメンバーを識別するための列を含む「submission_collaborators」のテーブルがあり、その組み合わせが主キーで、各列が外部キーです。

Briefs(Brief_ID, ...)
Submissions(Submission_ID, Brief_ID REFERENCES Briefs, ...)
Members(Member_ID, ...)
Submission_Collaborators(Submission_ID REFERENCES Submissions,
                         Member_ID REFERENCES Members,
                         PRIMARY KEY (Submission_ID, Member_ID)
                        )

したがって、要件は、次のクエリが行を返さないようにすることです。

SELECT s.brief_id, c.member_id, COUNT(*)
    FROM submissions AS s JOIN submission_collaborators AS c
         ON s.submission_id = c.submission_id
    GROUP BY s.brief_id, c.member_id
    HAVING COUNT(*) > 1

これは、CREATE ASSERTION (2 番目のバリアント) に埋め込んだのと同じクエリです。追加情報 (簡単なタイトル、提出タイトル、メンバー名、さまざまな日付など) を掘り出すこともできますが、問題の核心は、表示されるクエリがデータを返してはならないということです。

于 2009-03-17T13:22:47.717 に答える
0

あなたが持っているのは三者関係です。あなたがする必要があるのは、主キーで A と B と C を結び付けるテーブルを用意することです。主キーは複製できないため、各 A と各 B に対して 1 つの C のみが存在するように強制されます。これにより、探していた一意のコレクションが作成されます。

次のテーブル構造が得られます。

A's({A_ID}, ...)
B's({B_ID}, ...)
C's({C_ID}, ...)
A_B_C_Relation({[A_ID], [B_ID], [C_ID]}, ...)

中括弧内は主キー、大括弧内は外部キーです。

詳細については、こちらをご覧ください。

于 2009-03-17T12:09:59.403 に答える
0

TableA の ID を TableB に追加し、それを主キーに追加し、TableB と TableC についても同じことを行います。

編集:

この回答の最初の部分は、A から B への制約で機能すると思います。ただし、B と C の間に、A の PK も保持するリンク テーブルを配置します。そうすれば、A:B が 1:N になり、制約が適用されます。

于 2009-03-17T12:03:31.120 に答える
-1

単純な宣言的参照整合性制約ではこれを行うことができないと思います。ロジックを適用する最善の方法は、トリガーを使用してビジネス制約を実装し、ルールに違反する挿入または更新をロールバックすることです。

于 2009-03-17T12:05:44.657 に答える