2009-06-28 5 views
11

私は、複数の「タイプ」のユーザーを持つ組織のデータベースを設計しています。最初は、ユーザーテーブルを1つだけ作成しました。ただし、すべてのユーザーは共通の情報(名、姓、ユーザー名、パスワードなど)を共有していますが、各ユーザータイプにはすべてのユーザーに適用されない1つまたは2つの追加フィールドが必要です。これらの追加のフィールドを作成してNULLに設定することはできますが、フィールドは外部キーであり、そのために問題が発生しています。MySQLの質問 - 複数のタイプのユーザー(1つのテーブルまたは複数のユーザー)を処理する方法?

このような状況はどのように処理されますか?

ありがとうございます!

答えて

9

あなたの本能がNULLSのたくさんの大きなテーブルを作成しないために右側にあります。これは、ストレージ/リトリーブ/保守の観点からもデータ検証の観点からも悪い考えです(詳細は後で説明します)。

二つの最も一般的なapprocaches:

1)は、「ユーザータイプ」フィールドを含む、その中のすべての共通フィールドを持つユーザーテーブルを持っています。次に、余分なフィールドを含むユーザータイプごとに別のテーブルを作成します。すべてのユーザーには、ユーザーテーブルと特定のユーザータイプテーブルの1つ以上の行があります。これは、ストレージとクイックログインで最も正規化され、最も効率的です。これにより、制約や外部キーを使用して、各ユーザータイプに必要な情報がすべて利用可能になるようにすることもできます。

2)すべての共通フィールドを含むユーザーテーブルを用意してください。 UserAttributesのような別のテーブルがあり、userid、key、およびvalueのフィールドがあります。特定のユーザーのための余分なメタデータはすべてここに保存できます。これには、新しいユーザータイプまたはメタデータを追加して各ユーザータイプに格納するデータベースの管理が不要になるという利点があります。ただし、DBレベルでのデータ検証はできません。

+0

ありがとう、dj_segfault。 私はあなたのオプション#1を使い、共通のフィールドを持つユーザーテーブルと、より多くの「特定の」ユーザーテーブルによって参照されるuserTypeフィールドを作成しました。 NULLSは間違いなく頭痛を引き起こしていました、私は今それらを取り除くことがうれしいです! – littleK

+0

私は間違っている(私は間違っている)場合は、誰かが共通のフィールドは、fname、lname、電子メール、pwのような "ユーザー"レベルにあったような方法で自分のデータを格納する場合... 。 1つのクエリでより多くのユーザー固有の情報を取得する方法はありませんか?それ以上の特定の情報を得るには、ユーザータイプに基づいて常に2番目のクエリが使用されます。 – ackerchez

+0

@ackerchez確かにあります。すべての情報を取得するために必要なのは、UIDが何であれ、メインユーザーテーブルを持つすべてのユーザータイプ固有のユーザーテーブルを内部結合することだけです。そのユーザー・タイプではない表の列はNULLになります。 –

4

このような関係モデルは、この問題を解決するのに役立つかもしれない "継承"をサポートしていません(ただし、PostgreSQLなどのいくつかのDBエンジンは継承をサポートします)。

私は最初に自分自身に質問しました - 少なくともいくつかのケースでは、異なる種類のユーザーが同じコンテキストで表示できる必要がありますか?その場合、複数のテーブルに「共通の列」をコピーして貼り付けることはできません(少なくとも外部キーを介して単一のテーブルに取り込むことができる整合性チェックを損なうことはありません)。

2番目の質問です - ユーザーは複数の役割を持つことができますか?多くの場合、は珍しいですが、完全に不可能ではありません。従業員はサプライヤまたは顧客でもあります。

このような質問に私が他の方法で鋭い答えを得ることができない場合、私は共通のフィールドだけでusersテーブルを設定します。ベータ・テスター、顧客、そして私がユーザーに持つことができる他の種類と役割のテーブルを別々のテーブルに分け、残りのものを拾うためにユーザーテーブルに外部キーを加えました。

正規化されたスキーマは現在流行っていませんが、何十年も忠実に私に仕えてきました。私はそれらに対して深い愛があります。特定の最適化が必要なときに非正規化します。思うかもしれません!-)。

ここでは役に立つかもしれない多少の非正規化は、usersテーブル内の各特定の使用の「主」または「単独」の役割を示す列挙型列です(NULL可能であり、最初からそれを持つのには十分な勢いだった...;)...しかし、私は特定のクエリのパフォーマンスが特定の最適化としてそれを必要とする場合には、スキーマをそのように設計するのではなく、最初にクエリからSELECT * FROMを使用しないことが重要な理由であることに注意してください。後でALTER TABLEを追加すると、そのSELECT *が壊れます! - )。

+0

アレックス、本当にありがとうございました。本当に助けになりました。私はあなたが提案したことを行い、共通のフィールドを持つテーブルと、各ユーザータイプの他の共通でないフィールドのテーブルを設定しました。私はusersテーブルにロール列挙列も追加しました。 ありがとう! – littleK

1

これは有名な正規化問題です。

ビジネスニーズに合った答えを見つけようとすると、この記事や他の人のことを覗いてみてください。

To normalize or not to normalize

+0

この記事のおかげで非常に助かりました。私はこの話題について非常に多くの質問をしており、多くの人に答えました。 ありがとう! – littleK

+0

+1を与えるつもりですが、リンクはもう働きません。それを更新しますか? –

+0

@Gabriel Wow - それが今まで働いていたかどうかわかりません。私はそれを正しい記事に更新しました – Brian

0

あなたは、高レベルの言語を使用していた場合は言っていなかったので、私はちょうどDB-のような例で、一般的な例をあげる:

データベースの設計が困難です。だから、これは素早く簡単な答えになるでしょう。

あなたの質問は、データ関係とデータベース設計に関する基本的な質問です。この回答を助けるための基本的なハウツーガイドを検索してください。あなたの情報がどのようにグループ化されているかを考え、他のセット(テーブル)からプライマリセット(テーブル)に "バック"をリンクすることが役立ちます。

したがって、ユーザーはユーザーであり、ユーザーのテーブルです。ユーザーに関連付けられた主な共通要素(列)が含まれている必要があります。

次に、この他の情報セット(パーミッションなど)は別のテーブルです。

この他の表に、参照先のユーザーを指す値(列)があることを確認してください。だから

- integer "id"  <--- unique, index column, auto-increment 
    - integer "user_id" <--- this is which user this belongs 
    - ... 
    - Boolean "can_write"   <--- example data column 
    - Boolean "can_read"   <--- example data column 
    - Boolean "can_reboot_system" <--- example data column 
    - etc, whatever you want 

:あなたはおそらく「インデックス」

(など、検索性能を向上させるために)それらの間例えば、ユーザのための「許可」テーブルのようなものを作成するために、データベースをお伝えしたいと思いますあなたは "SELECT * FROM user_table WHERE first_name = 'joe'(など)...ユーザーを取得することができます。その行を識別するための何らかの種類の 'id'値があることを願っています。さて、 'SELECT * FROM permissions where WHERE user_id =' nnnn '(そのユーザーIDは何でも)

ユーザーが1つのアクセス権セットしか持っていない場合は、追加の "id"カラムなしでそのuser_idを持つことができます。

+0

joej- データベースレベルでのアクセス許可の表現について考えたことはありません。確かに良いアイデアのように思える。今、私はちょうどユーザを参照する "ロール"テーブルを持っています(そして、私はそのロールをPHPコードで実行します)。私はあなたのアイデアが好きですが、私はそれをもっと使いたいと考えています。 ありがとう! – littleK

関連する問題