web-dev-qa-db-ja.com

1対1の関係では、外部キーはどこに配置する必要がありますか?

現在、プロジェクト管理システムのERDを設計しています。最高の基準を採用したいので、2つの実行可能なソリューションを最適なソリューションとして選択することはできません。

システムにアクセスできる2つのエンティティは、クライアントと従業員です。情報が異なるため、別のエンティティとして扱うことにしました。クライアントと従業員の両方のテーブルでユーザー名とパスワードのフィールドを見つけるのではなく、システムのユーザー用に単一のテーブルを用意するのが最善であると考えました。さらに、私が従わなければならない制約:

  • すべてのユーザーは、従業員とクライアントに限定されています。
  • ただし、すべての従業員がシステムのユーザーである必要はありません。

以下は、関係がまだ定義されていない次のエンティティです。

Entities

現在、ユーザーとクライアント、従業員とユーザーの間には1対1の関係しかない。私の質問は、外部キーをどこに配置すればよいですか? usersテーブルに2つの外部キー、つまりemployee_idとclient_idを配置する必要があります。これにより、ユーザーエンティティから関連するクライアントと従業員エンティティを見つけやすくなり、認証ルールをより簡単に定義できます。または、ユーザーテーブルを参照するクライアントと従業員に各外部キーを配置する必要があります。一度に使用できる外部キーが1つだけのテーブルに2つの外部キーを含めることが許容できるかどうかはわかりません。

5
Xegara

テーブルで相互に排他的な属性を持つことは許容されます。そのような属性のペアが1つしかない場合は、これが最も実用的な解決策になる可能性があります。

ただし、一部の人々はあなたの状況をサブタイプの問題と見なすかもしれません。このビューでは、スーパーセットエンティティがありません。(何か)のコレクションがあり、その一部はemployeesであり、一部はcustomersおよびその一部はusersでもあります。

従業員がたまたま顧客になった場合にどうなるかについても考えましたか?それはあなたのシステムにとって重要ですか、それとも偶然と見なされるものですか?

すべてのusersを1つのタイプの機能として扱うことが重要だと考える場合は、(something)を実装する必要がありますは現在テーブル定義から欠落しています。

次のERDを検討してください。

ERD

不足しているスーパーセットエンティティを指定した場合、everyemployeeは、これらの1つです。すべてのcustomer、したがってすべてのuser。これの難しい部分は、このスーパーセットの適切な名前を考え出すことですが、userからどの外部キーを追跡する必要があるかという問題を解決します。また、employeecustomerの間の接続が作成されます。 。

1
Joel Brown

ケースを1つではなく2つの問題と見なすと役立つ場合があります。最初の問題は、クラス-サブクラス(または、必要に応じて、タイプ-サブタイプ)の問題です。従業員とクライアントは明らかに、名前を付けなかったいくつかのスーパークラスのサブクラスです。私はそれらを人と呼びます。 ( subtypes タグを参照してください)。

2番目の問題は、個人とユーザーの間の1対1の関係です。 Personsテーブルがある場合、外部キーがどちらの方向に進むべきかという問題は、関係が一方の端では必須であり、もう一方の端ではオプションであるという事実によって決まります。 PersonIDをUsersテーブルに配置する場合、ここでNULLを使用する必要はありません。すべてのユーザーは人です。

ここで、最初の問題、クラスとサブクラスの問題に戻ります。理にかなっていると思われる理由により、従業員用とクライアント用の2つの別々のテーブルを選択しました。 Personsテーブルを追加する場合、私が提案したように、名前や電話番号などのいくつかの一般的な属性を、両方のサブクラステーブルではなくPersonsテーブルに格納すると便利です。

この手法には名前があります。文献では「クラステーブルの継承」と呼ばれています。ウェブで検索することも、SOで検索することもできます。

このような場合に役立つ「共有主キー」と呼ばれる2番目の手法があります。共有主キーを使用すると、EmployeesテーブルとClientsテーブルに独立したIDフィールドがなくなります。代わりに、PersonIDフィールドは、Personsテーブルを参照するFKとしての役割に加えて、EmployeesテーブルまたはClientsテーブルの主キーとして宣言されます。この手法は、IS-A関係を実装する場合に一般的です。

これには、新しい従業員またはクライアントを挿入するときに少し余分なプログラミングが必要ですが、それだけの価値があるかもしれません。

これで、状況に応じて、usersテーブルをPersonsテーブル、Employeesテーブル、またはClientsテーブルに結合できます。必要なユーザーのカテゴリのみが共同結果に表示されます。

0
Walter Mitty

私はこれをすぐに調べただけですが、最初の考えは、EmployeeIdおよびClientIdのUsersテーブルでNULL属性を利用することです。その後、必要に応じてデータを入力し、外部キーとして定義できます。

UserNameは、Usersテーブルの主キーです。

Usersテーブル内のEmployeeId、ClientId、および複合EmployeeId + ClientIdのUNIQUE属性を使用します。

これは、Usersテーブルの「Employee is also a Client」の問題に対処します。

0
Terry