2

前の質問から、nmの関係で複合主キーを使用することについていくつかのアイデアを得ました。私の状態は非常に似ていますが、少し異なります。

[Person]

    PERSON_ID: int, primary key
    CLIENT_ID: int, primary key
    Name: nvarchar(xx)
    primary_key( PERSON_ID, CLIENT_ID);

[Group]

    GROUP_ID: int
    CLIENT_ID: int
    Name: nvarchar(xx)
    primary_key( GROUP_ID, CLIENT_ID);

ここで、mysql-workbenchツールを使用してリレーションシップテーブルを生成すると、テーブルが作成されます。

オプション1:

    [PersonHasGroup]

    PERSON_ID: int 
    CLIENT_ID: int 
    GROUP_ID: int
    CLIENT1_ID: int
primary_key( PERSON_ID, CLIENT_ID, GROUP_ID, CLIENT1_ID);

私の場合、両方のclient_idは通常同じ値になるので、次のようにテーブルを編集しました

オプション2:

    [PersonHasGroup]

    PERSON_ID: int
    CLIENT_ID: int
    GROUP_ID: int
primary_key( PERSON_ID, CLIENT_ID, GROUP_ID);

それらは良い習慣ですか?私の他の同僚が好むのは少し異なります。彼らは使用します:

オプション3:

   [PersonHasGroup]
    PERSON_HAS_GROUP_ID: int, auto-increment
    CLIENT_ID: int        
    PERSON_ID: int, foreign key
    GROUP_ID: int, foreign key
primary_key( PERSON_HAS_GROUP_ID, CLIENT_ID);

私の関係が多対多の説明である場合、どのプラクティスが適切であるかを例を挙げて説明すると、非常に役立ちます:)

4

5 に答える 5

3

提示されたオプションの間で議論はないはずです。正解は1つありますが、その答えはビジネスルールによって異なります。

「私の場合、両方のclient_idは通常、同じ値になります」というあなたの声明は私に関係しています。通常のような用語は、システムを設計するときに役立ちません。あなたは絶対的な観点から話す必要があります。

CLIENT_IDが両方の関係で同じである必要がある場合は、オプション2(1つの単一のCLIENT_ID)が正しい設計です。

ただし、各関係が異なるCLIENT_IDに基づく可能性がある場合(おそらくまれですが可能です)、もちろん、2つの一意の名前のCLIENT_ID列を持つオプション1が必要です。(これのビジネスケースを想像することはできませんが、あなたのモデルはすでに非常に奇妙なので、よくわかりません)

あなたがあなたのビジネス要件を完全に説明しない限り、誰もあなたがどちらが正しいかを決定するのを手伝うことはできませんが、あなたはそれが不可能であることを示します。

オプション3はオプションと見なされるべきではありません-代理キーを導入する場合は、複合代理キーであってはなりません。

ジャンクションテーブルPKが別のテーブルの外部キーにならない限り、私は個人的にジャンクションテーブル(多対多の関係を解決するテーブル)の代理キーを作成することはありません。その場合、パフォーマンス上の理由から代理キーを作成する可能性がありますが、それは簡単な選択ではありません。代理キーを作成する場合は、主キーと代替キーの両方を宣言する必要があります。1つは自然合成キーを使用し、もう1つは代理キーを使用します。特定のグループ/個人のペアが1回だけ入力されるようにし、サロゲートも一意にする必要があります。

したがって、特定の状況でパフォーマンス上の理由から代理キーが必要な場合は、オプション1と2の両方を変更して代理キーを含めることができます。

オプション1A

[PersonHasGroup]
  PERSON_ID: int
  PERSON_CLIENT_ID: int
  GROUP_ID: int
  GROUP_CLIENT_ID: int
  PERSON_HAS_GROUP_ID: int
primary_key( PERSON_ID, PERSON_CLIENT_ID, GROUP_ID, GROUP_CLIENT_ID);
alternate_key( PERSON_HAS_GROUP_ID )

オプション2A

[PersonHasGroup]
  PERSON_ID: int
  CLIENT_ID: int
  GROUP_ID: int
  PERSON_HAS_GROUP_ID: int
primary_key( PERSON_ID, CLIENT_ID, GROUP_ID);
alternate_key( PERSON_HAS_GROUP_ID )

もちろん、どちらがプライマリでどちらが代替かを逆にすることもできます。

于 2012-08-16T03:52:00.160 に答える
2

簡単に参照できるように単一のIDを使用し、一意のペアに別の一意のキーを使用することを好みます。ワークベンチは使用されないため、プレーンSQLの最初のIDは次のとおりです。

CREATE TABLE person_has_group (
    person_has_group_id SERIAL,
    client_id BIGINT UNSIGNED NOT NULL REFERENCES clients (client_id),
    person_id BIGINT UNSIGNED NOT NULL,
    group_id BIGINT UNSIGNED NOT NULL,
    FOREIGN KEY (client_id, person_id) REFERENCES persons (client_id, person_id),
    FOREIGN KEY (client_id, group_id) REFERENCES groups (client_id, group_id),
    UNIQUE KEY (client_id, person_id, group_id)
);

そして、「ワークベンチ」でこのような何かを精査します。

[PersonHasGroup]
    PERSON_HAS_GROUP_ID: int, auto-increment
    CLIENT_ID: int        
    PERSON_ID: int, foreign key
    GROUP_ID: int, foreign key
    primary_key( PERSON_HAS_GROUP_ID)
    unique_key( CLIENT_ID, PERSON_ID, GROUP_ID);
于 2012-08-08T11:51:29.203 に答える
1

私がこれを正しく理解していれば、次のことが当てはまるはずです。

  • クライアントごとに1つずつ、複数のサーバー(DB)があります。

  • 各DBには、およびの独自の自動インクリメントがPersonIDありGroupIDます。

  • これらすべてを1つのマルチテナントDBに単純に(直接)インポートしようとしています。したがって、およびテーブルClientIDの主キーにあります。PersonGroup

これらのステートメントが正しくない場合は、残りを無視してください。

ここに画像の説明を入力してください

create table PersonGroup (
    PersonID integer
  , GroupID  integer
  , ClientID integer
);

alter table PersonGroup add constraint  pk_PersonGroup
            primary key (PersonID, GroupID, ClientID);

alter table PersonGroup add constraint fk1_PersonGroup
            foreign key (PersonID, ClientID) references Person(PersonID, ClientID);

alter table PersonGroup add constraint fk2_PersonGroup
            foreign key (GroupID, ClientID) references Group(GroupID, ClientID);
于 2012-08-16T20:42:15.677 に答える
0

重複がテーブルに挿入されないように列option 2も追加するので、より良いと思います。UNIQUE CONSTRAINT( PERSON_ID, CLIENT_ID, GROUP_ID)

于 2012-08-08T11:41:45.060 に答える
0

良い質問。ただし、最初にPersonテーブルとGroupテーブルを簡単に見てみましょう。

テーブルの名前を考えると、Personの各行は人を表しているようであり、 Groupの各行はグループを表しているようです。したがって、概念的には、 Client_IDを必要としない個人またはグループを識別するために、主キーの一部としてそれを必要としません。モデルで各人が( Person_IDに加えて)一意のClient_IDを持つ必要がある場合は、それを一意のフィールドにしますが、主キーには含めないでください。

状況は、グループテーブルとはもう少し混乱しています。問題は、なぜGroup_IDだけではグループを識別できないのかということです。(Client_IDフィールドは、グループをクライアントに関連付けています。しかし、この関係の性質は何ですか?各グループはクライアントによって作成されますか?この場合、Keyの一部としてClient_IDを使用する必要はなく、必要なだけです。それを外部キーとして持つために。それはメンバーシップ関係ですか?その場合、別のテーブルで表されるNからMの関係が必要です)。

次に、 PersonGroupの関係に到達します。NからMの関係は、常に両方のテーブルのPKとNからMの関係のプロパティ(メンバーシップの日付など)で構成されるテーブルに変換されます。この場合、Person_IDGroup_IDの2つのフィールドを持つテーブルがあれば十分であり、両方とも複合キーの一部です。

また、命名にも注意する必要があります。PersonH​​asGroupは何を表していますか?その人はグループを所有していますか?それを管理しますか?またはそれは単なるメンバーシップです。メンバーシップの場合は、「PersonGroup」のような単純なもので十分です。

エンティティが概念的に正しく表示されていることを確認してください。そうしないと、フィールドを主キーに追加したり、ニーズを完全に満たしていないテーブルをリンクしたりするという罠に陥ります。エンティティのプロパティをカプセル化したままにし、それらを混在させないでください。「現実の世界でエンティティを特定するにはどうすればよいですか?」と自問してください。..そこに、主キーがどうあるべきかについての答えがあります。「私の場合、両方のclient_idは通常同じ値になります」のようなものは、概念が正しく表示されておらず、それらが混同されて冗長性と誤った関係が生じていることを示しています。

最後に、不十分に設計されたデータベースがあなたに渡され、新しいリンクやエンティティを紹介するように求められることがあることを理解しています。私のアドバイスは、可能な限り修正を試みることです。それは長期的にあなたを救うでしょう。

したがって、私の意見では、以前のデザインは、この質問のデザインと比較してはるかに優れたデザインです。

于 2012-08-16T19:08:26.263 に答える