So modellieren Sie die Vererbung zweier Tabellen in MySQL


14

Ich habe einige Tabellen, in denen ich Daten speichere, und abhängig von der Art der Person (Arbeiter, Zivilist), die meine Arbeit erledigt hat, möchte ich sie in einer eventTabelle speichern. Jetzt retten diese Jungs ein Tier (es gibt eine animalTabelle).

Schließlich möchte ich einen Tisch zur Aufbewahrung des Ereignisses haben, dass ein Mann (Arbeiter, Zivilist) ein Tier gerettet hat, aber sollte ich einen Fremdschlüssel hinzufügen oder wissen, wie hoch der idWert des Zivilisten oder Arbeiters ist, der die Arbeit ausgeführt hat?

Nun, bei diesem Entwurf weiß ich nicht, wie ich sagen soll, welche Person den Job gemacht hat, wenn ich nur eine Art von Person (auch bekannt als bürgerlich) hätte. Ich würde das civil_idTal nur in einer personSpalte in dieser letzten Tabelle aufbewahren ... aber wie Weiß ich, ob es sich um einen Zivil- oder einen Arbeitstisch handelt? Brauche ich einen anderen "Zwischentisch"?

Wie spiegelt sich das Design des folgenden Diagramms in MySQL wider?

Bildbeschreibung hier eingeben

Zusätzliche Details

Ich habe es folgendermaßen modelliert:

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

Gibt es jedoch eine Möglichkeit, Nullen loszuwerden?

Die Fragen, die ich habe, sind:

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 ;

Hier ist eine aktualisierte SQLFiddle .


Was ist der Zweck einer Tabelle, TYPE_PERSONwenn sie nur eine Spalte enthält?
JW 웃


@cMinor - Sie fragen sich, "wie Sie die ID des Bürgers oder Arbeitnehmers kennen, der die Arbeit erledigt hat?" Weißt du eigentlich, wer den Job im wirklichen Leben gemacht hat (oder imaginär, wenn dies eine Hausaufgabe ist)? Haben Sie genügend Quelldaten?

Ich gewöhne mich an die Vererbung, also habe ich eine Tischperson erstellt, die die Arten von Personen (Arbeiter, Zivilist) enthält. Dann in der Ereignistabelle: Wie beziehe ich mich auf eine Person, abhängig davon, wie der Job ausgeführt wurde (Zivilist oder Arbeiter)?
cMinor

1
Ich glaube, Sie würden bessere Ratschläge in Datenbankadministratoren bekommen
Pieter Geerkens

Antworten:


13

Da ich das Diagramm gemacht habe, antworte ich besser;)

Aktuelle relationale Datenbanken unterstützen die Vererbung leider nicht direkt, daher müssen Sie sie in "einfache" Tabellen umwandeln. Hierfür gibt es im Allgemeinen drei Strategien:

  1. Alle Klassen 1 in einer einzelnen Tabelle mit NULL-fähigen nicht gemeinsamen Feldern.
  2. Betonklassen 2 in separaten Tabellen. Abstrakte Klassen haben keine eigenen Tabellen.
  3. Alle Klassen in separaten Tabellen.

Weitere Informationen zu den tatsächlichen Auswirkungen und Vor- und Nachteilen finden Sie unter den in meinem ursprünglichen Beitrag angegebenen Links. Kurz gesagt sollte (3) jedoch Ihre Standardeinstellung sein, es sei denn, Sie haben einen bestimmten Grund für einen der beiden anderen. Sie können die (3) in der Datenbank einfach so darstellen:

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

Leider können Sie mit dieser Struktur personweder ein civilnoch ein haben worker(dh Sie können die abstrakte Klasse instanziieren), und Sie können auch ein erstellen person, das beides civil und ist worker. Es gibt Möglichkeiten , die früheren auf Datenbankebene zu erzwingen, und in einem DBMS , dass Stützen Einschränkungen latenten 3 auch diese können innerhalb der Datenbank erzwungen werden, aber dies ist einer der wenige Fälle , in denen mit der Anwendungsebene Integrität tatsächlich vorzuziehen sein könnten .


1 person , civilund workerin diesem Fall.

2 civil und workerin diesem Fall ( personist "abstrakt").

3 Welche MySQL nicht.


Wie kann letzteres in DBMS erzwungen werden, das zurückgestellte Einschränkungen unterstützt? (Es ist einer Person nicht erlaubt, beides zu sein civilund worker)
Gima

@Gima Bitte folgen Sie dem Link, den ich in der Antwort angegeben habe.
Branko Dimitrijevic

Sie behaupten, dass aktuelle relationale Datenbanken keine Vererbung unterstützen. Was ist mit postgresql? postgresql.org/docs/9.6/static/ddl-inherit.html
Höhepunkt

@Climax Mir ist PostgreSQL bekannt, aber die Implementierung ist nur teilweise. Von Ihrem Link: "Andere Arten von Einschränkungen (eindeutige, Primärschlüssel- und Fremdschlüsseleinschränkungen) werden nicht vererbt."
Branko Dimitrijevic

1
@naaz Fremdschlüssel sind in civilund vorhanden worker. Vielleicht haben Sie die Kurzschrift-Syntax verpasst (nur REFERENCESohne FOREIGN KEY)?
Branko Dimitrijevic

5

Es ist nicht erforderlich, Civil_ID und Worker_ID zu unterscheiden. Verwenden Sie weiterhin die Personen-ID als Schlüssel für alle drei Tabellen: Person, Civil und Worker. Fügen Sie der Person eine Spalte PersonType mit den beiden Werten "Civil" und "Worker" hinzu.

Dies repräsentiert nun die beiden Unterklassen CivilClass und WorkerClass der abstrakten Basisklasse PersonClass als Unterentitäten Civil und Worker der Basisentität Person. Sie erhalten eine gute Übereinstimmung zwischen dem Datenmodell in der DB und dem Objektmodell in der Anwendung.


Ich habe eine SQL- Geige erstellt. Sqlfiddle.com/#!2/1f6a4/1, aber ich weiß nicht, wie ich an einem anderen Tisch teilnehmen soll. Könnten Sie bitte Ihre Antwort hier in der SQL-Geige angeben?
cMinor

Es gibt keine "Unterscheidung" civil_idund worker_id- sie sind dasselbe wie person_id, nur anders benannt - schauen Sie auf den FK1(Fremdschlüssel-) Marker vor ihnen.
Branko Dimitrijevic

4

Ihr Fall ist eine Instanz der Klassen- / Unterklassenmodellierung. Oder, wie Sie es in ER dargestellt haben, Generalisierung / Spezialisierung.

Es gibt drei Techniken, die Ihnen beim Entwerfen von MySQL-Tabellen helfen, um diesen Fall abzudecken. Sie heißen Single Table Inheritance, Class Table Inheritance und Shared Primary Key. Sie können sie in der Registerkarte Info vom entsprechenden Tag in SO nachlesen.

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

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

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

Die Vererbung einzelner Tabellen ist in einfachen Fällen hilfreich, in denen das Vorhandensein von NULL-Werten keine Probleme verursacht. Die Vererbung von Klassentabellen ist für kompliziertere Fälle besser. Gemeinsamer Primärschlüssel ist ein guter Weg, um Eins-zu-Eins-Beziehungen zu erzwingen und Verknüpfungen zu beschleunigen.


1

Sie können eine Personentypentabelle erstellen und ein Feld zu allen Tabellen hinzufügen, für die die Typenerzwingung erforderlich ist. Dann erstellen Sie Fremdschlüssel. Hier ist ein Beispiel aus Ihrer ...

    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...
    );
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.