MySQLの2つのテーブルの継承をモデル化する方法


14

データを保存するテーブルがいくつかあり、仕事をした人のタイプ(労働者、市民)に応じてeventテーブルに保存しますが、今ではこれらの人が動物を救いanimalます(テーブルがあります)。

最後に、男(労働者、市民)が動物を救ったというイベントを保存するテーブルが必要ですが、お辞儀をする必要がありidますか、または仕事をした市民または労働者の価値を知る方法はありますか?

さて、このデザインでは、どの人が仕事をしたかをどのように関連付けるかわかりません、私はこの最後の表の列にcivil_idベールを保存するだけの人(別名市民)しかいpersonません...しかし、どのように市民か労働者かを知っている場合、他の「中間」テーブルが必要ですか?

次の図の設計をMySQLに反映する方法は?

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

追加の詳細

次の方法でモデル化しました。

DROP    TABLE IF EXISTS `tbl_animal`; 
CREATE TABLE `tbl_animal` (
    id_animal       INTEGER     NOT NULL PRIMARY KEY AUTO_INCREMENT,
    name            VARCHAR(25) NOT NULL DEFAULT "no name",
    specie          VARCHAR(10) NOT NULL DEFAULT "Other",
    sex             CHAR(1)     NOT NULL DEFAULT "M",
    size            VARCHAR(10) NOT NULL DEFAULT "Mini",
    edad            VARCHAR(10) NOT NULL DEFAULT "Lact",
    pelo            VARCHAR(5 ) NOT NULL DEFAULT "short",
    color           VARCHAR(25) NOT NULL DEFAULT "not defined",
    ra              VARCHAR(25) NOT NULL DEFAULT "not defined",
    CONSTRAINT `uc_Info_Animal` UNIQUE (`id_animal`)           
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;


INSERT INTO `tbl_animal` VALUES (1,'no name', 'dog', 'M','Mini','Lact','Long','black','Bobtail');
INSERT INTO `tbl_animal` VALUES (2,'peluchin', 'cat', 'M','Mini','Lact','Long','white','not defined');
INSERT INTO `tbl_animal` VALUES (3,'asechin', 'cat', 'M','Mini','Lact','Corto','orange','not defined');

DROP    TABLE IF EXISTS `tbl_person`;  
CREATE TABLE `tbl_person` (
    type_person  VARCHAR(50) NOT NULL primary key        
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;
INSERT INTO `tbl_person` (type_person) VALUES ('Worker');
INSERT INTO `tbl_person` (type_person) VALUES ('Civil');



DROP    TABLE IF EXISTS `tbl_worker`;  
CREATE TABLE `tbl_worker`(
    id_worker           INTEGER  NOT NULL PRIMARY KEY,
    type_person         VARCHAR(50) NOT NULL , 
    name_worker         VARCHAR(50) NOT NULL ,    
    address_worker      VARCHAR(40) NOT NULL DEFAULT "not defined",     
    delegation          VARCHAR(40) NOT NULL DEFAULT "not defined",
    FOREIGN KEY (type_person)               REFERENCES `tbl_person` (type_person),
    CONSTRAINT `uc_Info_worker` UNIQUE (`id_worker`)           
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

INSERT INTO `tbl_worker` VALUES (1,'Worker','N_CEDENTE1', 'DIR Worker 1', 'DEL');
INSERT INTO `tbl_worker` VALUES (2,'Worker','N_worker1', 'DIR Worker 2', 'DEL');
INSERT INTO `tbl_worker` VALUES (3,'Worker','N_worker2', 'address worker','delegation worker'); 


DROP    TABLE IF EXISTS `tbl_civil`; 
CREATE TABLE `tbl_civil`(
    id_civil                        INTEGER  NOT NULL PRIMARY KEY,
    type_person         VARCHAR(50) NOT NULL ,
    name_civil                      VARCHAR(50)  ,
    procedence_civil                VARCHAR(40)  NOT NULL DEFAULT "Socorrism",    
  FOREIGN KEY (type_person)             REFERENCES `tbl_person` (type_person),
    CONSTRAINT `uc_Info_civil` UNIQUE (`id_civil`)           
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;


INSERT INTO `tbl_civil`  VALUES (1,'Civil','N_civil1' , 'Socorrism');


CREATE TABLE `tbl_event` (
    id_event     INTEGER NOT NULL,
    id_animal    INTEGER NOT NULL,
    type_person  VARCHAR(50) NOT NULL , 
    date_reception DATE DEFAULT '2000-01-01 01:01:01',
    FOREIGN KEY (id_animal)   REFERENCES `tbl_animal`    (id_animal),
    FOREIGN KEY (type_person )  REFERENCES `tbl_person`   (type_person ),
    CONSTRAINT `uc_Info_ficha_primer_ingreso` UNIQUE (`id_animal`,`id_event`)     
)ENGINE=InnoDB  DEFAULT CHARSET=utf8;

INSERT INTO `tbl_event` VALUES (1,1, 'Worker','2013-01-01 01:01:01' );
INSERT INTO `tbl_event` VALUES (2,2, 'Civil','2013-01-01 01:01:01' );

しかし、nullを取り除く方法はありますか?

私が持っているクエリは次のとおりです。

SELECT  a.*,b.*,z.*
FROM    tbl_event a
        left JOIN tbl_worker b
            ON a.type_person = b.type_person
        left JOIN tbl_animal z
            ON   z.id_animal = a.id_animal ;

SELECT  a.*,b.*,z.*
FROM    tbl_event a
        left JOIN tbl_civil b
            ON a.type_person = b.type_person
        left JOIN tbl_animal z
            ON   z.id_animal = a.id_animal ;

これが更新されたsqlfiddleです。


テーブルTYPE_PERSONに列が1つしかない場合のテーブルの目的は何ですか?
JW웃

1
これのフォローアップ:stackoverflow.com/questions/15128222/…

@cMinor-あなたは「仕事をした市民または労働者のIDを知る方法」を求めています。実際に誰が仕事をしたかを知っていますか(または、宿題の場合は想像上の)。十分なソースデータがありますか?

私は継承に慣れてきたので、人々のタイプ(労働者、市民)を保持するテーブルパーソンを作成し、イベントテーブルで、仕事の仕方(市民または労働者)に応じて人を参照する方法は?
cMinor

1
私はあなたがデータベース管理者に、より良いアドバイスを得ると考えている
ピーターGeerkens

回答:


13

ダイアグラムを作成したので、答えた方がよい;)

残念ながら、現在のリレーショナルデータベースは継承を直接サポートしていないため、「プレーン」テーブルに変換する必要があります。これを行うには、一般に3つの戦略があります。

  1. NULL可能な非共通フィールドを持つ単一テーブルのすべてのクラス1
  2. 個別のテーブルの具象クラス2。抽象クラスには、独自のテーブルがありません。
  3. 個別のテーブルのすべてのクラス。

これが実際に何を意味し、いくつかの長所と短所の詳細については、元の投稿で提供されているリンクをご覧ください。次のように、データベースで(3)を簡単に表すことができます。

CREATE TABLE person (
    person_id int PRIMARY KEY
    -- Other fields...
);

CREATE TABLE civil (
    civil_id int PRIMARY KEY REFERENCES person (person_id)
    -- Other fields...
);

CREATE TABLE worker (
    worker_id int PRIMARY KEY REFERENCES person (person_id)
    -- Other fields...
);

CREATE TABLE event (
    event_id int PRIMARY KEY,
    person_id int REFERENCES person (person_id)
    -- Other fields...
);

あいにく、この構造personは、どちらcivilでもないworker(つまり、抽象クラスをインスタンス化することができる)を持たせ、また、両方personあるを作成させます。前者をデータベースレベルで実施する方法があり、遅延制約3をサポートするDBMS では後者もデータベース内で実施できますが、これはアプリケーションレベルの整合性を使用することが実際に望ましい少数のケースの1つです。 civilworker


1 personcivilおよびworkerこの場合。

2 civilおよびworkerこの場合(person「抽象」です)。

3 MySQLがサポートしていないもの。


遅延制約をサポートするDBMSで後者をどのように実施できますか?(人が両方civilとであることを許可しないworker
ギマ

@Gima回答で提供したリンクをたどってください。
ブランコディミトリエビッチ

現在のリレーショナルデータベースは継承をサポートしていないと主張します。postgresqlはどうですか?postgresql.org/docs/9.6/static/ddl-inherit.html
クライマックス

@Climax PostgreSQLは知っていますが、その実装は部分的なものにすぎません。リンクから:「他の種類の制約(一意、主キー、および外部キーの制約)は継承されません。」
ブランコディミトリエビッチ

1
@naaz外部キーは、両方に存在civilしてworker。おそらく、あなたは短い手構文(ちょうど逃しREFERENCESなしにFOREIGN KEY)?
ブランコディミトリエビッチ

5

個別のCivil_IDとWorker_IDは不要です。Person、Civil、およびWorkerの3つのテーブルすべてのキーとしてPerson-IDを使用し続けるだけです。2つの値「Civil」と「Worker」を使用して、PersonType列をPersonに追加します。

これは、抽象基本クラスPersonClassの2つのサブクラスCivilClassおよびWorkerClassを、基本エンティティPersonのサブエンティティCivilおよびWorkerとして表します。DB内のデータモデルとアプリケーション内のオブジェクトモデルとの間に良好な対応関係が得られます。


sqlfiddle sqlfiddle.com/#!2/1f6a4/1を実行しましたが、他のテーブルに参加する方法がわかりません。ここでsqlfiddleで答えを示してください。
午前

「明確な」ものはなくcivil_idworker_id-と同じものでperson_id、名前が異なるだけです-それらのFK1前にある(外部キー)マーカーを見てください。
ブランコディミトリエビッチ

4

あなたのケースは、クラス/サブクラスモデリングのインスタンスです。または、ERで図式化したように、一般化/専門化。

このケースをカバーするmysqlテーブルの設計に役立つ3つのテクニックがあります。これらは、単一テーブル継承、クラステーブル継承、共有プライマリキーと呼ばれます。SOの対応するタグから情報タブでそれらを読むことができます。

/programming//tags/single-table-inheritance/info

/programming//tags/class-table-inheritance/info

/programming//tags/shared-primary-key/info

単一テーブルの継承は、NULLの存在が問題を引き起こさない単純な場合に役立ちます。クラステーブルの継承は、より複雑な場合に適しています。共有主キーは、1対1の関係を強制し、結合を高速化するための良い方法です。


1

個人タイプテーブルを作成し、タイプの適用が必要なすべてのテーブルにフィールドを追加できます。次に、外部キーを作成します。これはあなたのものに由来する例です...

    CREATE TABLE person_type (
        person_type_id int PRIMARY KEY
        -- data: 1=civil, 2=worker
        -- Other fields (such as a label)...
    );

    CREATE TABLE person (
        person_id int PRIMARY KEY
        person_type_id int FOREIGN KEY REFERENCES person_type (person_type_id)
        -- Other fields...
    );

    CREATE TABLE civil (
        civil_id int PRIMARY KEY REFERENCES person (person_id)
        person_type_id int FOREIGN KEY REFERENCES person (person_type_id)
        -- Other fields...
    );

    CREATE TABLE worker (
        worker_id int PRIMARY KEY REFERENCES person (person_id)
        person_type_id int FOREIGN KEY REFERENCES person (person_type_id)
        -- Other fields...
    );

    CREATE TABLE event (
        event_id int PRIMARY KEY,
        person_id int REFERENCES person (person_id)
        -- Type is optional here, but you could enforce event for a particular type
        person_type_id int FOREIGN KEY REFERENCES person (person_type_id)
        -- Other fields...
    );
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.