web-dev-qa-db-ja.com

データベース設計-人と組織

私たちが構築しているソフトウェアには「お客様」がいます。顧客は個人または組織のいずれかです。

私は本当にこれに最適なスキーマを作成したいです。

私はこれらの考慮事項を持っています。

  1. 個人は1つ以上の連絡先(電話、電子メールなど)を持つことができます
  2. 人は1つ以上のアドレスを持つことができます
  3. 組織は1つ以上の連絡先(電話、電子メールなど)を持つことができます
  4. 組織は1つ以上のアドレスを持つことができます
  5. 組織には、1人以上の個人を関連付けることができます。

アプリを適切にスケーリングしたいので、スキーマはこの選択に合うはずです。

私は次のようなことを達成しようとしています。

SELECT * FROM Customers + a few joins.

1. Person | NULL | John Doe | Primary Organisation Contact | Primary Address

2. Organisation | Acme Ltd | Jane Doe | Primary Organisation Contact | Primary Address

上記を関連付けるための最適なスキーマを作成するにはどうすればよいですか?

大まかなビジュアルスキーマ階層をアタッチしました。そして、間違いなく私は間違いを犯しています。

http://snag.gy/yshxE.jpg

個人か組織かに応じて、結婚した一連の結果を取得することは可能ですか?

個人および連絡先/住所を顧客に参加させるのは簡単ですが、組織の主要な連絡先/住所に参加するにはどうすればよいですか?

スパイダーダイアグラムのようなスキーマを実現する簡単な方法はありますか?

6
user492681

連絡先と会社でいくつかのアプリを実際に構築したことからのいくつかの洞察。

まず、アウトラインにいくつかのユースケースがありません。あなたが必ずしもカバーしているわけではない、私が長年にわたって遭遇したカラフルなものの中で:

  1. 一部の組織には、部門、子会社など、下位組織があります。
  2. 一部の人々はいくつかの組織に属しています。 VPのように、XYZ、ABCの会長、および自営業のCEO /コンサルタントのいずれも-うまくいけば、それぞれパートタイムで。
  3. 一部の人々は、実際には所属していない組織の連絡先になることができます。例えば。知名度の高いコンサルタントがプロジェクトリーダーとして一時的に採用されると、彼は実際にはXYZに所属していなくても、XYZ社の主要な連絡先になる可能性があります。
  4. 人々はまた、サブピープルを持つことができます。後者は同じ会社に属していてもいなくてもかまいません。たとえば、XYZの私たちのVPは、ABCについて彼に連絡しない限り、彼のメインの秘書を向こうに通すことを好むかもしれません。または個人的にコンサルティング業務のため-非常に忙しい人ですが、そのような人がいます。
  5. 一部の組織には、連絡先が関連付けられていません。これは、たとえば、連絡先がまだ識別されていない見込みのある会社(営業担当者向け)のリストを出力するアプリで発生する可能性があります。
  6. 逆に、連絡先に組織を含めることはできません。たとえば、消費者。

第二に、あなたの概要は顧客に言及しているので、顧客は会社でも(肉体的)人物でもよいことに注意してください。ダイアグラムに基づいてその部分がカバーされているようですので、次に進みましょう。

次のステップが「注文」テーブルなどの会計に関連するものを追加することである場合、会計に関連するすべてが会社、連絡先、製品、価格などに関連付けられていることに注意してください時間。これらの詳細はあらゆる種類のカラフルな方法で進化する可能性があり、頻繁に起こる設計ミスは、完全な正規化された設計を作成し、必要に応じてテーブルを更新するだけであると想定することです。だめだ。税務署員から請求書を印刷するように依頼され、会社ABCが価格Qで会計されたときに、会社XYZが価格PであるとITが言った場合、あなたは非常にうんざりしています。また、同様の設計ミスにより変更された、年に1回のアーカイブされたアカウントとクローズされたアカウントから始めないでください。

第3に、正規化しすぎると発生する可能性があるUI/UXの問題に非常に注意してください。一般的なユーザーが手に持っているアプリ(Outlook:Outlook)のように機能しない場合、Joeが新しい仕事に就いたときに、XYZのすべての従業員の会社をABCに変更することから離れて、十分に訓練されていない秘書になります。私は実際にこれが起こるのを見ました、そしてそれはかなりの光景ではありませんでした。 (あなたが疑問に思っているかもしれないので、彼女は彼女の仕事を続けました。)

最後に、避けられない重複する会社、連絡先、その他の多くのカラフルなものをマージすることから始めないでください。これらを念頭に置き、スキーマがveryveryであることを確認してくださいwillが発生するためです。

今...実際に...

個人的に、私はこの場合、正規化に実際に目を向けるようになりました。連絡先/会社は、学校で教えられたようにDB設計と美しく正規化されたデータが、リソースの浪費、過度に複雑なクエリ、および途方もなく複雑なUIの形で問題を引き起こすレシピの1つです。とにかく、それは私見ではありません。

まず、連絡先テーブルを作成し、氏名、必要に応じてdisplay_name、company_name、address、phone、cell_phone、email、email2、secretary_name、secretary_phoneなどのフィールドを入力します。Outlookで連絡先を作成するときに使用できる場合は、それはおそらくそこに属しています。

私は会社の表に言及しなかったことに気付くでしょう。これは、通常、連絡先テーブルと会社のテーブルの間の強い結びつきを望まないためです。必要な場合は1つ追加し、company_nameに加えてcopmany_idを追加します。ただし、削除セットのnullの外部キーにします。また、データベースレベルで、company_nameに非常に緩く関連付けられていることを確認してください。それをフロントエンドレベルで維持します。これにより、秘書が誤って複数の連絡先の会社を変更することを防ぎます。

物事を正気に保つ。リストに合理的に表示されるもの(つまり、select * from contact where ... limit 10)、クエリの対象、または表に頻繁にあるはずの情報。参加しません、nada。クエリ、結果の反復、完了。

本当ににゴミを追加したい場合、2つのオプションがあります。

1つは、extra_contact_detailsテーブルを作成することです。これは、EAVテーブル、company_name、address、phoneなどのフィールドの完全なロード、または正規化されたビットと断片のホグウォッシュにすることができます。どちらのオプションを選択しても、やりすぎないでください。どちらの場合も、追加の(潜在的に複雑な)クエリが作成され、UIを作成すると、厄介なプログラミングの問題が山積みになります。ここで絶対に重要なのは、この方法を使用する場合、常にOutlookで作業してきた秘書がそれを理解する必要があるということです。

もう1つは、実際に前もってお勧めしますが、連絡先テーブルに「extra_contact_details」というテキストフィールドを追加して、そのまま使用することです。正規化はまったくありません。 1組の主要な詳細。頻繁に使用される二次的な詳細。プレーンテキストとして余分なもの。秘書はそれを取得します。エンドユーザーはそれを手に入れます。できました。

最後に、特定の時点でデータのバージョンを保存する必要がある場合は、キーの詳細の値を必ず複製してください。読み取り:挿入したときとまったく同じように印刷するために必要なもの。

11

男、私はデータベースの本が最初の章でパーティーモデルをカバーすることを望みます。

時間にかなりの価値がある場合は、HayのEnterprise Model PatternsまたはSilverstonのData Model Resource Bookを読んでください。サファリで安く見つけることができます。

テーブル継承についても読んでください:

http://martinfowler.com/eaaCatalog/singleTableInheritance.html

Nullが気に入らない場合は、クラステーブルの継承を使用してください。

パーティーは人、組織、自動エージェントを表します:

Party
 id
 name

Individual : Party

Organization : Party

AutomatedAgent : Party

顧客は、パーティーが演じる役割です。たとえば、誰かがあなたのサプライヤーになる可能性があります。あなたは彼らを従業員として雇い、解雇すると、彼らはあなたの顧客になります。

あなたは彼らがあなたと一緒に販売注文をしたかどうかから彼らの「顧客」を引き出すか、PartyRoleを使って顧客として彼らを宣言することができます。

PartyRelationshipは、パーティー間の関係を表します。

PartyRelationship
 fromParty
 toParty
 fromDate
 toDate (nullable)

OrganizationContact : PartyRelationship

Employment : PartyRelationship

アドレスは、物理アドレスと仮想アドレスを表します。

Address
 id

EmailAddress : Address
 emailAddress

WebAddress : Address
 url

TelephoneNumber : Address
 telephoneNumber

MailingAddress : Address
 suiteOrApartment
 street
 city
 Zip

人々は多くの連絡方法を持っています:

ContactMethod
 party
 address
 fromDate
 toDate (nullable)
 telephoneExtension (nullable)

Hibernateのようなツールを使用することを強くお勧めします。

5
Neil McGuigan

パーティーデータモデルを見てください。これは要件を満たしているはずです。

http://www.tdan.com/view-articles/5014/

2
nvogel

このようなものはどうですか?

addresses
    id              unsigned int(P)
    street1         varchar(50)
    street2         varchar(50)
    city_id         unsigned int(F cities.id)
    Zip             varchar(6)
    lat             double
    lon             double

cities
    id              unsigned int(P)
    state_id        unsigned int(F states.id)
    name            varchar(50)

countries
    id              char(2)(P)
    iso3            char(3)(U)
    iso_num         char(3)(U)
    name            varchar(45(U)

customers
    id              unsigned int(P)
    parent_id       unsigned int(F customers.id) (Allow NULL)
    name            varchar(50) // John Doe, ABC Company, etc.

customers_addresses
    id                  unsigned int(P)
    customer_id         unsigned int(F customers.id)
    address_id          unsigned int(F addresses.id)

customers_email_addresses
    id                  unsigned int(P)
    customer_id         unsigned int(F customers.id)
    email_address_id    unsigned int(F email_addresses.id)

customers_phone_numbers
    id                  unsigned int(P)
    customer_id         unsigned int(F customers.id)
    phone_number_id     unsigned int(F phone_numbers.id)

email_addresses
    id              unsigned int(P)
    address         varchar(255)

phone_numbers
    id              unsigned int(P)
    area_code       char(3)
    exchange        char(3)
    station         char(4)
    extension       varchar(10)

states
    id              unsigned int(P)
    country_id      char(2)(F countries.id)
    code            char(2)

電話番号と郵便番号は北アメリカ諸国向けであり、他の国では変更する必要があります。

customersテーブルのサンプルデータを次に示します。

+----+-----------+---------------+
| id | parent_id |     name      |
+----+-----------+---------------+
|  1 |      NULL | ABC Company   |
|  2 |      NULL | XYZ Company   |
|  3 |         1 | John Doe      |
|  4 |         1 | Jane Doe      |
|  5 |         2 | John Q Public |
|  6 |      NULL | JKL Company   |
+----+-----------+---------------+

組織には常にNULL parent_idがあります。個人は、NULL parent_id(組織に関連付けられていない場合)または非NULL parent_id(組織に関連付けられている場合)を持つことができます。特定のニーズには他の変更が必要になる場合があります...

SQLの例:

SELECT * FROM customers c
LEFT JOIN customers_addresses ca ON c.id = ca.customer_id
LEFT JOIN customers_email_address ce ON c.id = ce.customer_id
LEFT JOIN customers_phone_numbers cp ON c.id = cp.customer_id
LEFT JOIN cities ON ca.city_id = cities.id
LEFT JOIN states ON cities.state_id = states.id
LEFT JOIN countries ON states.country_id = countries.id
WHERE c.id = 1
1
Benny Hill