2

現在、ソフトウェアのアドレス帳モジュールを作成しています。非常に柔軟なアドレス帳構成をサポートするように、データベースをセットアップしました。

必要なすべてのタイプの n エントリを作成できます。タイプとは、ここでは「メール」、「住所」、「電話」などのデータを意味します。

「contact_profiles」という名前のテーブルがあります。

これには 2 つの列しかありません。

id           Primary key
date_created DATETIME

そして contact_attributes というテーブルがあります。これはもう少し複雑です:

id       PK
#profile (Foreign key to contact_profiles.id)
type     VARCHAR describing the type of the entry (name, email, phone, fax, website, ...) I should probably change this to a SET later.
value    Text (containing the value for the attribute).

たとえば、ユーザーのテーブルから、これらのプロファイルにリンクできるようになりました。しかし、ここから問題が発生します。

現時点では、取得する値ごとに JOIN を作成する必要があります。何らかの方法でビューを作成する可能性はありますか?それにより、タイプの as 列で結果が得られますか?

だから今、私は次のようなものを得るでしょう

#profile type    value
1        email   name@domain.tld
1        name    Sebastian Hoitz
1        website domain.tld

しかし、次のような結果が得られるとよいでしょう。

#profile email           name            website
1        name@domain.tld Sebastian Hoitz domain.tld

最初にこのようなテーブル レイアウトを作成したくない理由は、追加するものが常にある可能性があり、同じタイプの複数の属性を持つことができるようにしたいからです。

これを動的に変換する可能性があるかどうか知っていますか?

より良い説明が必要な場合は、お知らせください。

4

6 に答える 6

4

Entity-Attribute-Valueと呼ばれるデータベース設計を再発明しました。この設計には、あなたが発見した弱点を含め、多くの弱点があります: 属性ごとに 1 つの列を持つ従来の形式でクエリ結果を再現することは非常に困難です。

これはあなたがしなければならないことの例です:

SELECT c.id, c.date_created,
 c1.value AS name,
 c2.value AS email,
 c3.value AS phone,
 c4.value AS fax,
 c5.value AS website
FROM contact_profiles c
 LEFT OUTER JOIN contact_attributes c1
  ON (c.id = c1.profile AND c1.type = 'name')
 LEFT OUTER JOIN contact_attributes c1
  ON (c.id = c1.profile AND c1.type = 'email')
 LEFT OUTER JOIN contact_attributes c1
  ON (c.id = c1.profile AND c1.type = 'phone')
 LEFT OUTER JOIN contact_attributes c1
  ON (c.id = c1.profile AND c1.type = 'fax')
 LEFT OUTER JOIN contact_attributes c1
  ON (c.id = c1.profile AND c1.type = 'website');

LEFT OUTER JOIN属性ごとに別のものを追加する必要があります。クエリを作成するときに、属性を知っている必要があります。LEFT OUTER JOIN属性を必須にする方法がないため、and notを使用する必要がありますINNER JOIN(単純に column を宣言するのと同じですNOT NULL)。

格納されている属性を取得し、アプリケーション コードを記述して結果セットをループ処理し、各属性のエントリを持つオブジェクトまたは連想配列を作成する方がはるかに効率的です。nこのようにすべての属性を知る必要はなく、 -way 結合を実行する必要もありません。

SELECT * FROM contact_profiles c
  LEFT OUTER JOIN contact_attributes ca ON (c.id = ca.profile);

EAV 設計を使用しない場合、このレベルの柔軟性が必要な場合はどうすればよいか、コメントで尋ねましたか? 無制限のメタデータの柔軟性が本当に必要な場合、SQL は正しいソリューションではありません。いくつかの代替手段を次に示します。

  • XML またはYAMLTEXT形式で構造化されたすべての属性を含む BLOB を保存します。
  • すべてのエンティティが動的属性を持つことができるSesameのようなセマンティック データ モデリング ソリューションを使用します。
  • データベースを放棄し、フラット ファイルを使用します。

EAV とこれらの代替ソリューションはどれも大変な作業です。データ モデルにこの程度の柔軟性が本当に必要な場合は、非常に慎重に検討する必要があります。メタデータ構造を比較的変更しないものとして扱うことができれば、はるかに単純になるからです。

于 2008-12-15T18:25:53.793 に答える
1

このクエリで各ユーザーのメール、名前、ウェブサイトなどを 1 つだけ表示するように制限している場合は、サブクエリを使用します。

SELECT cp.ID profile
  ,cp.Name
  ,(SELECT value FROM contact_attributes WHERE type = 'email' and profile = cp.id) email
  ,(SELECT value FROM contact_attributes WHERE type = 'website' and profile = cp.id) website
  ,(SELECT value FROM contact_attributes WHERE type = 'phone' and profile = cp.id) phone
FROM contact_profiles cp

SQL Server を使用している場合は、PIVOTも確認できます。

複数の電子メール、電話などを表示したい場合は、各プロファイルに同じ数が必要であるか、空白になることを考慮してください。

タイプ列も除外します。contact_attribute_types「電子メール」、「ウェブサイト」などを保持するという名前のテーブルを作成します。次に、contact_attribute_types.id整数値をcontact_attributesテーブルに保存します。

于 2008-12-15T18:20:47.250 に答える
0

この質問に対する唯一の正解はありません。特定の組織またはアプリケーションについて、企業が収集したい連絡方法の数、情報をどの程度最新のものにしたいか、およびどの程度の柔軟性があるかを知る必要があるためです。に投資する意思があります。

もちろん、ここにいる多くの人は、平均的なビジネスが何をしたいのかについてある程度の推測をすることができますが、本当の答えは、あなたのプロジェクトやユーザーが何に興味を持っているかを見つけることです.

ところで、「最善」に関するすべてのアーキテクチャの質問には、この種のコスト、利益、およびリスク分析が必要です。

于 2009-05-09T00:31:07.373 に答える
0

ドキュメント指向データベースのアプローチがますます一般的になっているため、それらの 1 つを使用して、このすべての情報を 1 つのエントリに格納し、余分な結合とクエリをすべて削除することができます。

于 2010-05-17T12:29:34.257 に答える
0

次のようなクエリを生成する必要があります。

select #profile,
       max(case when type='email' then value end) as email,
       max(case when type='name' then value end) as name,
       max(case when type='website' then value end) as website
from mytable
group by #profile

ただし、#profile ごとに各タイプの 1 つの値のみが表示されます。DBMS には、MAX の代わりに使用してすべての値をカンマ区切りの文字列として連結できる関数があるか、記述できる可能性があります。

この種のデータ モデルは、既に述べた理由から、通常は避けるのが最善です。

于 2008-12-15T18:24:06.573 に答える
0

連絡先の種類ごとにビューを作成します

テーブル全体から取得したすべての情報が必要な場合、特定の連絡先タイプのサブセットが必要な場合は、ビューから取得します。

パラメータの 1 つとしてインテント {all, phone, email, address} を取り、データを取得するストアド プロシージャを作成します。すべてのアプリ コードは、このストアド プロシージャを呼び出してデータを取得します。また、新しいタイプが追加された場合 (非常にまれですが、別のビューを作成し、この sproc のみを変更します)。

複数の小規模/中規模システムに同様の設計を実装しましたが、問題はありませんでした。

何か不足していますか?これは些細なことに思えますか?

編集:

私が見逃していたものがわかります...あなたは同時に正規化され、非正規化されようとしています。レコードをプルするためのビジネス ルールの残りの部分がわかりません。電話/電子メール/アドレスなどに複数の値またはnull値を持つプロファイルを持つことができます。データ形式を同じに保ち、再びsprocを使用して必要な特定のビューを作成します。ビジネス ニーズの変化に応じて、データをそのままにして、それにアクセスするための別の sproc を作成するだけです。

于 2008-12-15T18:35:55.880 に答える