変数エンティティをリレーショナルテーブルに変換する方法がわからない


9

はじめにおよび関連情報:

次の例は、私が直面している問題を示しています。

動物には人種があり、猫ででもかまいません。シャムまたはペルシャのいずれかです。ジャーマンシェパードまたはラブラドールレトリバーにすることができます。

動物は強力なエンティティですが、その人種は2つの提供された値(猫または犬)の1つを持つことができる属性です。 これらの値はどちらも複雑です(問題を説明するためにここでは犬/猫のタイプのみを追加しましたが、猫/犬の名前やその他の要素もある場合があります)。

問題:

この例では、リレーショナルテーブルを作成する方法がわかりません。

問題を解決するための私の努力:

問題を表す陳の表記法を使用してERダイアグラムを描画しようとしましたが、初心者であるため、正しく行ったかどうかはわかりません。ここに私が持っているものがあります:

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

間違ったものを描いた場合はお詫び申し上げます。その場合は訂正してください。私は単に「無料のソリューション」を手に入れたいのではなく、将来この問題を自分で解決できるように対処する方法を学びたいと思っています。

頭に浮かぶのは、猫用と犬用の2つの別々のテーブルを作成することだけです。また、Animalテーブルの人種属性には、または犬の値のみが格納されます。このようなもの:

Animal< # Animal_ID, race, other attributes >
Cat < # Cat_ID, $ Animal_ID, breed >
Dog < # Dog_ID, $ Animal_ID, breed >

私は自分の解決策について本当に気分が悪く、それが間違っているのではないかと心配しています。

質問:

  • 私の例をどのようにしてER図に変換できますか?
  • そのER図をリレーショナルテーブルに変換する方法は?

さらに情報が必要な場合はコメントを残してください。できるだけ早く投稿を更新します。私はここでかなり新しいので、適切なタグを追加してください。

ありがとうございました。


1
EERダイアグラムからテーブルへの変換は、1986年のTJTeorey、D.Yang、JPFry:A論理設計手法を使用した、リレーショナルデータベースの拡張エンティティリレーションシップモデルのこのペーパーに記載されています。それは簡単で、私の好きな論文の1つです。
miracle173 2014年

回答:


11

このシナリオの適切な構造は、サブクラス/継承モデルであり、この回答で提案した概念の値の異種混合順序リストとほぼ同じです。

この質問で提案されているモデルは、Animalエンティティにraceすべてのタイプに共通のタイプ(つまり)とプロパティが含まれているという点で、実際には非常に近いものです。ただし、2つの小さな変更が必要です。

  1. Cat_IDおよびDog_IDフィールドをそれぞれのエンティティから削除します。

    ここで重要な概念であることすべてがあるAnimalにかかわらず、raceCatDogElephant、など。その出発点を考えると、以下の理由により、特定raceAnimalは本当に個別の識別子を必要としません。

    1. Animal_IDユニークです
    2. CatDog、および任意の追加のrace将来追加エンティティは、それだけでは完全に任意の特定を表すものではありませんAnimal。親エンティティに含まれる情報と組み合わせて使用​​した場合にのみ意味がありAnimalます。

    したがって、Animal_ID中性CatDogなどのエンティティがPKとにFKバックの両方であるAnimalエンティティ。

  2. タイプの違いbreed

    理由だけで2つのプロパティが同じ名前がありません共有必ずしも意味し、それらの性質が同じである名前があっても、同じであることを意味し、このような関係を。この場合は、何が本当に持っていることは、実際にあるCatBreedDogBreed別々の「タイプ」として

最初のメモ

  1. SQLはMicrosoft SQL Serverに固有です(つまり、T-SQLです)。つまり、データ型はすべてのRDBMSで同じではないため、データ型には注意してください。たとえば、私は使用してVARCHARいますが、標準のASCIIセット以外のものを格納する必要がある場合は、実際に使用する必要がありますNVARCHAR
  2. 「タイプ」テーブルのIDフィールドは(RaceCatBreed、及びDogBreed)ありません彼らは、静的なルックアップ値ですアプリケーション定数(すなわち、それらはアプリケーションの一部である)であるため、自動インクリメント(T-SQLの観点すなわちIDENTITYを)データベースでありenum、C#(または他の言語)ではs として表されます。値が追加される場合、それらは制御された状況で追加されます。アプリケーションを介して受信するユーザーデータの自動インクリメントフィールドの使用を予約します。
  3. 私が使用する命名規則は、メインクラス名で始まり、サブクラス名が続く各サブクラステーブルに名前を付けることです。これは、テーブルの編成に役立つだけでなく、サブクラステーブルとメインエンティティテーブルの関係を(FKを見ずに)明確に示すのに役立ちます。
  4. ビューに関する注意事項については、最後の「最終編集」セクションを参照してください。

「レース」特有のアプローチとしての「ブリード」

レース固有の図としての品種
この最初のテーブルセットは、ルックアップ/タイプテーブルです。

CREATE TABLE Race
(
  RaceID INT NOT NULL PRIMARY KEY
  RaceName VARCHAR(50) NOT NULL
);

CREATE TABLE CatBreed
(
  CatBreedID INT NOT NULL PRIMARY KEY,
  BreedName VARCHAR(50),
  CatBreedAttribute1 INT,
  CatBreedAttribute2 VARCHAR(10)
  -- other "CatBreed"-specific properties as needed
);

CREATE TABLE DogBreed
(
  DogBreedID INT NOT NULL PRIMARY KEY,
  BreedName VARCHAR(50),
  DogBreedAttribute1 TINYINT
  -- other "DogBreed"-specific properties as needed
);

この2番目のリストは、メインの「動物」エンティティです。

CREATE TABLE Animal
(
  AnimalID INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
  RaceID INT NOT NULL, -- FK to Race
  Name VARCHAR(50)
  -- other "Animal" properties that are shared across "Race" types
);

ALTER TABLE Animal
  ADD CONSTRAINT [FK_Animal_Race]
  FOREIGN KEY (RaceID)
  REFERENCES Race (RaceID);

この3番目のセットのテーブルは、以下のそれぞれRaceの定義を完了する補足的なサブクラスエンティティですAnimal

CREATE TABLE AnimalCat
(
  AnimalID INT NOT NULL PRIMARY KEY, -- FK to Animal
  CatBreedID INT NOT NULL, -- FK to CatBreed
  HairColor VARCHAR(50) NOT NULL
  -- other "Cat"-specific properties as needed
);

ALTER TABLE AnimalCat
  ADD CONSTRAINT [FK_AnimalCat_CatBreed]
  FOREIGN KEY (CatBreedID)
  REFERENCES CatBreed (CatBreedID);

ALTER TABLE AnimalCat
  ADD CONSTRAINT [FK_AnimalCat_Animal]
  FOREIGN KEY (AnimalID)
  REFERENCES Animal (AnimalID);


CREATE TABLE AnimalDog
(
  AnimalID INT NOT NULL PRIMARY KEY, -- FK to Animal
  DogBreedID INT NOT NULL, -- FK to DogBreed
  HairColor VARCHAR(50) NOT NULL
  -- other "Dog"-specific properties as needed
);

ALTER TABLE AnimalDog
  ADD CONSTRAINT [FK_AnimalDog_DogBreed]
  FOREIGN KEY (DogBreedID)
  REFERENCES DogBreed (DogBreedID);

ALTER TABLE AnimalDog
  ADD CONSTRAINT [FK_AnimalDog_Animal]
  FOREIGN KEY (AnimalID)
  REFERENCES Animal (AnimalID);

共有breedタイプを使用するモデルは、「補足事項」セクションの後に示されています。

その他の注意事項

  1. の概念はbreed、混乱の焦点のようです。jcolebrandによって(質問へのコメントで)breed異なるraces 間で共有されるプロパティが提案されました。他の2つの答えは、モデルにそのように統合されています。ただし、の値breedはの異なる値間で共有されないため、これは誤りですrace。はい、私は他の2つの提案モデルraceがの親にすることでこの問題を解決しようとしていることを認識していbreedます。これは関係の問題を技術的に解決しますが、一般的でないプロパティについて何をすべきかというモデリング全体の問題や、raceを持たないを処理する方法の解決には役立ちませんbreed。ただし、そのようなプロパティがすべての場所に存在することが保証されている場合Animals、そのためのオプションも含めます(下記)。
  2. vijaypとDavidN(同一と思われる)によって提案されたモデルは、次の理由で機能しません。
    1. 彼らのどちらか
      1. 一般的でないプロパティを保存することを許可しない(少なくともの個々のインスタンスでは許可しないAnimal)、または
      2. すべてののすべてのプロパティをエンティティにrace格納する必要があります。Animalこれは、このデータを表す非常にフラットな(そしてほぼ非リレーショナルな)方法です。はい、人々はいつもこれを行っていますが、それはrace、特定raceのレコードではなく、そのレコードの特定のレコードに関連付けられているフィールドを知るために、特定のプロパティの行ごとに多くのNULLフィールドを持つことを意味します。
    2. 彼らは追加のために許可されていないraceのをAnimal持っていない、将来的にbreedプロパティとして。ALL場合でも、そしてAnimalsが持っているbreed、それが原因以前について指摘されているものに構造を変更しないでしょうbreed。それbreedに依存しているrace(すなわちbreedCatと同じものではありませんbreedのためにDog)。

共通/共有プロパティアプローチとしての「ブリード」

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

  1. 以下のSQLは、上記のモデルと同じデータベースで実行できます。

    1. Race表は同じです
    2. Breedテーブルには新しいです
    3. 3つのAnimalテーブルには、2
  2. 現在でBreedは一般的なプロパティであるとしてもRace、メイン/親エンティティで(技術的に関係なく正しいとしても)言及しなかったのは正しくないようです。だから、両方のRaceIDBreedIDで表現されていますAnimal2。間の不整合を防止するためにRaceIDに留意Animal2BreedID異なるためであることをRaceID、私は両方でFKを追加したところRaceID, BreedIDで、これらのフィールドの一意性制約を参照するBreedテーブル。私は通常、FKがUNIQUE CONSTRAINTを指すことを軽視しますが、これはそうするためのいくつかの有効な理由の1つです。UNIQUE CONSTRAINTは論理的には「代替キー」であり、これをこの用途に有効にします。また、BreedテーブルにはまだのPKがあることに注意してくださいBreedID
    1. 結合フィールドでPKのみを使用し、UNIQUE CONSTRAINTを使用しない理由は、同じBreedID値をの異なる値にわたって繰り返すことができるためですRaceID
    2. PKとUNIQUE CONSTRAINTの切り替えを行わない理由は、これがの唯一の使用方法でBreedIDはない可能性があるためです。Breedそのため、をRaceID使用せずにの特定の値を参照することは可能です。
  3. 次のモデルは機能しますが、共有の概念に関して2つの潜在的な欠陥がBreedあります(そして、私が- Race固有のBreedテーブルを好む理由です)。
    1. のすべての値がBreed同じプロパティを持つという暗黙の仮定があります。このモデルでは、Dog「品種」とElephant「品種」の間で異なる特性を持つ簡単な方法はありません。ただし、これを行う方法はまだあります。これは「最終編集」セクションに記載されています。
    2. Breed複数の種族でa を共有する方法はありません。それが望ましいかどうか(または、動物の概念ではないが、おそらくこのタイプのモデルを使用する他の状況では可能か)はわかりませんが、ここではできません。
CREATE TABLE Race
(
  RaceID INT NOT NULL PRIMARY KEY,
  RaceName VARCHAR(50) NOT NULL
);

CREATE TABLE Breed
(
  BreedID INT NOT NULL PRIMARY KEY,
  RaceID INT NOT NULL, -- FK to Race
  BreedName VARCHAR(50)
);

ALTER TABLE Breed
  ADD CONSTRAINT [UQ_Breed]
  UNIQUE (RaceID, BreedID);

ALTER TABLE Breed
  ADD CONSTRAINT [FK_Breed_Race]
  FOREIGN KEY (RaceID)
  REFERENCES Race (RaceID);

CREATE TABLE Animal2
(
  AnimalID INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
  RaceID INT NOT NULL, -- FK to Race, FK to Breed
  BreedID INT NOT NULL, -- FK to Breed
  Name VARCHAR(50)
  -- other properties common to all "Animal" types
);

ALTER TABLE Animal2
  ADD CONSTRAINT [FK_Animal2_Race]
  FOREIGN KEY (RaceID)
  REFERENCES Race (RaceID);

-- This FK points to the UNIQUE CONSTRAINT on Breed, _not_ to the PK!
ALTER TABLE Animal2
  ADD CONSTRAINT [FK_Animal2_Breed]
  FOREIGN KEY (RaceID, BreedID)
  REFERENCES Breed (RaceID, BreedID);


CREATE TABLE AnimalCat2
(
  AnimalID INT NOT NULL PRIMARY KEY, -- FK to Animal
  HairColor VARCHAR(50) NOT NULL
);

ALTER TABLE AnimalCat2
  ADD CONSTRAINT [FK_AnimalCat2_Animal2]
  FOREIGN KEY (AnimalID)
  REFERENCES Animal2 (AnimalID);

CREATE TABLE AnimalDog2
(
  AnimalID INT NOT NULL PRIMARY KEY,
  HairColor VARCHAR(50) NOT NULL
);

ALTER TABLE AnimalDog2
  ADD CONSTRAINT [FK_AnimalDog2_Animal2]
  FOREIGN KEY (AnimalID)
  REFERENCES Animal2 (AnimalID);


最終編集(できれば;-)

  1. のタイプ間で異なるプロパティを処理する可能性(およびその難しさ)に関しては、同じサブクラス/継承の概念をメインエンティティとして使用するBreedこと可能Breedです。この設定ではBreed、テーブルは、すべてのタイプに共通する特性を持っているでしょうBreed(ただのようなAnimalテーブル)とRaceIDの種類を表すことになりBreed(それはでないと同じようAnimal表)。次にBreedCat、などのサブクラステーブルがありますBreedDog。小規模なプロジェクトの場合、これ「オーバーエンジニアリング」と見なされる可能性がありますが、メリットが得られる状況のオプションとして言及されています。
  2. どちらの方法でも、エンティティ全体へのショートカットとしてビューを作成すると役立つ場合があります。たとえば、次のことを考慮してください。

    CREATE VIEW Cats AS
       SELECT  an.AnimalID,
               an.RaceID,
               an.Name,
               -- other "Animal" properties that are shared across "Race" types
               cat.CatBreedID,
               cat.HairColor
               -- other "Cat"-specific properties as needed
       FROM    Animal an
       INNER JOIN  AnimalCat cat
               ON  cat.AnimalID = an.AnimalID
       -- maybe add in JOIN(s) and field(s) for "Race" and/or "Breed"
  3. 論理エンティティの一部ではありませんが、少なくともレコードが挿入および更新されている時期を把握するために、テーブルに監査フィールドを含めることはかなり一般的です。だから実際的には:
    1. CreatedDateフィールドが追加されるだろうAnimalテーブル。AnimalCatトランザクション内で両方のテーブルに挿入される行を同時に実行する必要があるため、このフィールドはサブクラステーブル(など)では必要ありません。
    2. LastModifiedDateフィールドが追加されるだろうAnimalテーブルとすべてのサブクラスのテーブル。このフィールドは、その特定のテーブルが更新された場合にのみ更新されます。特定AnimalCatので更新が発生したが、発生しなかった場合は、のフィールドのみが設定されます。AnimalAnimalIDLastModifiedDateAnimalCat

2
どういうわけか、あなたは私の問題が何であるかを正確に理解したと感じます。あなたのリンクされた答えを見て、注意深く調べます。テーブルの単純な定義も素晴らしいでしょう(SQLクエリが多すぎて現時点では記述できない場合)。SQLクエリまたはテーブル定義で投稿を更新する場合は、コメントを残してください。ありがとうございました。宜しくお願いします。
AlwaysLearningNewStuff 2014年

1
私はあなたの答えを私の実際のケースに適用しようとしています。私が盲目的にあなたの指示に従うなら、私は私のデザインをさらに最適化する機会を逃すかもしれないと私は信じています。私の質問を完全に理解し、優れた回答を提供することができたので、私の最新の質問を見ていただきたいと思います。将来の読者にも役立つように、一般的なデータモデルを使用する質問を作成しました。見つからない場合はコメントを残してください。ご迷惑をおかけして申し訳ありません...
AlwaysLearningNewStuff

@AlwaysLearningNewStuffこんにちは。以前にこのメッセージを受け取りましたが、すぐにメッセージを読む時間がありませんでした。上記の名前をクリックして新しい質問を見つけることができました。質問のすべてが表示されます:-)。
ソロモンルツキー2016年

私はこの質問に言及していました。簡単に言えば、私は共通の属性を持つ3つのエンティティーを持っているDので、あなたの答えからメソッドを適用したいと思いました。2つのエンティティにはE、3番目のエンティティには存在しない共通の属性があります。この事実を無視して標準ソリューションを適用する必要がありますか、それとも設計をさらに最適化する方法はありますか?
AlwaysLearningNewStuff

4

まず、ERモデリングとリレーショナルモデリングを区別するためにうまくやっています。多くの初心者はそうしません。

ここでは、ウェブ上の役立つ記事を検索するために使用できる流行語があります。

あなたのケースは、クラス/サブクラスの古典的なケース、または、必要に応じてタイプ/サブタイプです。

ERモデリングで使用されるフレーズは「一般化/専門化」です。そして、多くの記事はこれをEER(Enhanced Entity-Relationship)モデリングと呼ばれるものの下で示しています。これは、ピーターチェンのERモデリングの元のプレゼンテーションにはありませんでした。後で追加されました。PDF形式のgen / specのかなり良い要約については、ここをクリックしてください

次に、クラス/サブクラスのケースをリレーショナルモデリングに変換するときに、テーブルを設計します。複数のアプローチがあります。2つの主要なアプローチは、単一テーブル継承とクラステーブル継承と呼ばれます。それぞれに長所と短所があります。これら2つのデザインの最も優れたプレゼンテーションは、Martin Fowlerからのものです。ここここで彼の概要を見ることができます

単一テーブル継承の大きな利点は、単純さです。すべて1つのテーブルに格納されています。大きな欠点はNULLが多いことです。これはスペースと時間を浪費し、ロジックを混乱させる可能性があります。

クラステーブルの継承には結合が必要ですが、結合は単純で高速です。特に、共有主キーと呼ばれる手法を使用する場合、サブクラステーブルのPKはスーパークラステーブルのPKのコピーになります。スーパークラスデータとサブクラスデータを結合するサブクラスごとにビューを作成できます。

最後に、この領域には、あなたのような質問をまとめて収集するタグがあります。
ここにあります:


1
+1困惑しているのは、テーブル図に主キーがないことです。特に「classTableInheritance」では、これらのすべてのテーブルが同じ主キーで接続されていることがわかりません。
miracle173 2014年

@ miracle173は有効なポイントです。何らかの理由で、Fowlerは図にPKとFKを含めません。この詳細を提供する他の記事がクラステーブル継承の下にあります。クラステーブル継承のすべての実装が、それを共有主キーと組み合わせるわけではありません。私はそれをお勧めします。挿入時の作業は少し増えますが、結合された検索時の方が簡単で高速です。
Walter Mitty、2014年

3

私は可能なデザインについて

テーブル Race

RaceId- PK- Int
RaceName - Varchar(50)

テーブル Breed

BreedId - PK- Int
RaceId - FK - Int
BreedName - varchar(50)

テーブル Animal

AnimalId - PK- Int
BreedId - FK - Int
Other Columns....

上記のこれらのPKは、自動インクリメント列になります。Animalテーブルの他の列には、それに応じた名前を付けることができます。

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


さらに、速度を改善するために後のインデックスを容易にするために、AnimalテーブルにRaceおよびType(トリガーである可能性があります)のキーを持つフィールドを追加します。
フェリペアルカシバル2014年

0

あなたの現在の方法は悪くありません。ただし、後でレース(鳥、魚など)を追加する場合は、それぞれに個別のテーブルを作成するのが面倒な場合があります。私は次のようなものをお勧めします:

Animal < # Animal_ID, Breed_ID, other attributes >
Breed < # Breed_ID, Race_ID >
Race < # Race_ID >

品種は、私の理解では、人種は1つだけです。したがって、品種を動物テーブルに保存すると、品種テーブルに参加することでレースを決定できるようになります。明らかに、必要に応じて、他の属性(名前、説明など)をBreedテーブルとRaceテーブルに追加します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.