it-swarm-eu.dev

Jak modelovat dědičnost dvou tabulek MySQL

Mám několik tabulek, kde ukládám data a v závislosti na typu osoby (pracovníka, civilní), která vykonala práci, kterou chci uložit do tabulky event, nyní tito lidé zachraňují zvíře (existuje animal tabulka).

Nakonec chci mít stůl pro uložení události, kterou člověk (pracovník, občan) zachránil zvíře, ale luk bych měl přidat cizí klíč nebo jak zjistit hodnotu id hodnoty civilního nebo pracovníka to odvedlo práci?

Teď, v tomto návrhu nevím, jak vztahovat, která osoba udělala práci, pokud bych měla jen druh člověka (aka civilní), jen bych si uložil civil_id vale ve sloupci person v této poslední tabulce ... ale jak zjistit, zda to bylo civilní nebo dělnické, potřebuji jinou „mezistupeň“ tabulku?

Jak promítnout design následujícího diagramu v MySQL?

enter image description here

Další detaily

Modeloval jsem to následujícím způsobem:

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' );

Existuje však způsob, jak se zbavit nulových hodnot?

Dotazy, které mám, jsou:

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 ;

Zde je aktualizovaný sqlfiddle.

16
cMinor

Od doby, kdy jsem vytvořil diagram, jsem lepší odpověď;)

Aktuální relační databáze bohužel nepodporují dědičnost přímo, proto ji musíte transformovat do „obyčejných“ tabulek. Obecně existují 3 strategie:

  1. Všechny třídy1 v jedné tabulce s neobvyklými poli, která umožňují NULL.
  2. Betonové třídy2 v samostatných tabulkách. Abstraktní třídy nemají vlastní tabulky.
  3. Všechny třídy v samostatných tabulkách.

Pro více informací o tom, co to ve skutečnosti znamená a o některých kladech a záporech, se podívejte na odkazy uvedené v mém původní příspěvek , ale ve zkratce by měl být (3) pravděpodobně váš výchozí, pokud nemáte konkrétní důvod jeden z dalších dvou. Můžete reprezentovat (3) v databázi jednoduše takto:

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...
);

Tato struktura vám bohužel umožní mít person, který není civil ani worker (tj. Můžete vytvořit instanci abstraktní třídy), a také vám umožní vytvořit person to znamená civil i worker. Existují způsoby vynutit první z nich na úrovni databáze a v DBMS, který podporuje odložená omezení3 i ten druhý může být vynucen v databázi, ale to je jeden z mála případů, kdy by použití integrity na úrovni aplikace mohlo být ve skutečnosti lepší.


1 person, civil a worker v tomto případě.

2 civil a worker v tomto případě (person je „abstraktní“).

3 Které MySQL ne.

15

Není třeba rozlišovat Civil_ID a Worker_ID; jen nadále používejte ID osoby jako klíč pro všechny tři tabulky: Osoba, Občan a Pracovník. Přidejte sloupec PersonType k osobě se dvěma hodnotami „Civil“ a „Worker“.

To nyní představuje dvě podtřídy CivilClass a WorkerClass abstraktní základní třídy PersonClass jako podřízené entity Civil a Worker základní entity Person. Dostanete pěknou korespondenci mezi datovým modelem v DB a objektovým modelem v aplikaci.

5
Pieter Geerkens

Váš případ je příkladem modelování třídy/podtřídy. Nebo, jak jste to znázornili v ER, zobecnění/specializace.

Existují tři techniky, které vám pomohou navrhnout tabulky mysql, které pokryjí tento případ. Říká se jim dědičnost jedné tabulky, dědičnost tabulky tříd a sdílený primární klíč. Můžete si je přečíst na kartě Informace z příslušné značky v SO.

https://stackoverflow.com/tags/single-table-inheritance/info

https://stackoverflow.com/tags/class-table-inheritance/info

https://stackoverflow.com/tags/shared-primary-key/info

Dědičnost jedné tabulky je užitečná pro jednoduché případy, kdy přítomnost NULL nezpůsobuje problémy. Dědičnost tabulky je lepší pro komplikovanější případy. Sdílený primární klíč je dobrý způsob, jak vynutit vzájemné vztahy a urychlit spojení.

4
Walter Mitty

Můžete vytvořit tabulku typu osoby a přidat pole ke všem tabulkám vyžadujícím vynucení typu. Poté vytvořte cizí klíče. Zde je příklad vycházející z vašeho ...

    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...
    );
1
Isometriq