web-dev-qa-db-fra.com

Comment modéliser l'héritage de deux tables MySQL

J'ai des tables où je stocke des données et selon le type de personne (travailleur, civil) qui a fait un travail, je veux le stocker dans une table event, maintenant ces gars sauvent un animal (il y a un animal table).

Enfin, je veux avoir une table pour stocker l'événement qu'un gars (travailleur, civil), a sauvé un animal, mais archet dois-je ajouter une clé étrangère ou comment connaître la valeur id du civil ou du travailleur qui a fait le boulot?

Maintenant, dans cette conception, je ne sais pas comment identifier la personne qui a fait le travail si, je n'avais qu'une sorte de personne (alias civile), je ne stockerais que le civil_id vale dans une colonne person dans ce dernier tableau ... mais comment savoir s'il était civil ou ouvrier, ai-je besoin d'un autre tableau "intermédiaire"?

Comment refléter la conception du diagramme suivant dans MySQL?

enter image description here

Détails supplémentaires

Je l'ai modélisé de la manière suivante:

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

Cependant, existe-t-il un moyen de se débarrasser des null?

Les requêtes que j'ai sont:

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 ;

Voici une mise à jour sqlfiddle.

16
cMinor

Depuis que j'ai fait le schéma, je ferais mieux de répondre;)

Les bases de données relationnelles actuelles ne prennent malheureusement pas directement en charge l'héritage, vous devez donc le transformer en tables "simples". Il existe généralement 3 stratégies pour le faire:

  1. Toutes les classes1 dans une seule table avec des champs non communs compatibles NULL.
  2. Classes de béton2 dans des tableaux séparés. Les classes abstraites n'ont pas leurs propres tables.
  3. Toutes les classes dans des tableaux séparés.

Pour en savoir plus sur ce que cela signifie réellement et certains avantages et inconvénients, veuillez consulter les liens fournis dans mon article d'origine , mais en un mot, le (3) devrait probablement être votre valeur par défaut, sauf si vous avez une raison spécifique pour l'un des deux autres. Vous pouvez représenter le (3) dans la base de données simplement comme ceci:

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

Malheureusement, cette structure vous permettra d'avoir un person qui n'est ni civil ni worker (c'est-à-dire que vous pouvez instancier la classe abstraite), et vous permettra également de créer un person c'est-à-dire à la fois civil et worker. Il existe des moyens pour appliquer le premier au niveau de la base de données et dans un SGBD qui prend en charge les contraintes différées3 même ce dernier peut être appliqué dans la base de données, mais c'est l'un des rares cas où l'utilisation de l'intégrité au niveau de l'application pourrait être préférable.


1 person, civil et worker dans ce cas.

2 civil et worker dans ce cas (person est "abstrait").

3 Ce que MySQL ne fait pas.

15

Il n'y a pas besoin de Civil_ID et Worker_ID distincts; continuez simplement à utiliser Person-ID comme clé pour les trois tables: Person, Civil et Worker. Ajoutez une colonne PersonType à Person avec les deux valeurs "Civil" et "Worker".

Cela représente désormais les deux sous-classes CivilClass et WorkerClass de la classe de base abstraite PersonClass en tant que sous-entités Civil et Worker de l'entité de base Person. Vous obtenez une belle correspondance entre le modèle de données dans la base de données avec le modèle d'objet dans l'application.

5
Pieter Geerkens

Votre cas est une instance de modélisation de classe/sous-classe. Ou, comme vous l'avez schématisé dans ER, généralisation/spécialisation.

Il existe trois techniques qui vous aideront à concevoir des tables mysql pour couvrir ce cas. Ils sont appelés héritage de table unique, héritage de table de classe et clé primaire partagée. Vous pouvez les lire dans l'onglet info de la balise correspondante dans 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

L'héritage de table unique est utile dans les cas simples où la présence de valeurs NULL ne pose pas de problème. L'héritage de table de classe est préférable pour les cas plus compliqués. La clé primaire partagée est un bon moyen d'imposer des relations un à un et d'accélérer les jointures.

4
Walter Mitty

Vous pouvez créer une table de type de personne et ajouter un champ à toutes les tables nécessitant l'application du type. Créez ensuite des clés étrangères. Voici un exemple dérivant du vôtre ...

    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