Come modellare l'ereditarietà di due tabelle MySQL


14

Ho alcune tabelle in cui memorizzo i dati e in base al tipo di persona (lavoratore, civile) che ha svolto un lavoro, voglio archiviarlo in un event tavolo, ora questi ragazzi salvano un animale (c'è un animaltavolo).

Infine, voglio avere un tavolo per archiviare l'evento in cui un ragazzo (lavoratore, civile), ha salvato un animale, ma a prua dovrei aggiungere una chiave esterna o come conoscere il idvalore del civile o del lavoratore che ha svolto il lavoro?

Ora, in questo progetto non so come mettere in relazione quale persona ha svolto il lavoro se, avessi solo un tipo di persona (aka civile), conserverei solo il civil_id valle in una personcolonna in quest'ultima tabella ... ma come so se era civile o lavoratore, ho bisogno di altro tavolo "intermedio"?

Come riflettere il design del seguente diagramma in MySQL?

inserisci qui la descrizione dell'immagine

Dettagli aggiuntivi

L'ho modellato nel modo seguente:

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

Tuttavia, c'è un modo per sbarazzarsi di null?

Le domande che ho sono:

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 ;

Ecco un sqlfiddle aggiornato .


qual è lo scopo della tabella TYPE_PERSONquando contiene solo una colonna?
JW 웃


@cMinor - Stai chiedendo "come sapere l'id del civile o del lavoratore che ha svolto il lavoro?" Sai davvero chi ha svolto il lavoro nella vita reale (o immaginaria, se si tratta di compiti a casa)? Hai dati di origine sufficienti?

Mi sto abituando all'eredità, quindi ho creato una persona da tavolo in grado di contenere i tipi di persone (lavoratore, civile), quindi nella tabella degli eventi, Come fare riferimento a una persona a seconda di come ha svolto il lavoro (civile o lavoratore)?
cMinor

1
Credo che
otterresti

Risposte:


13

Da quando ho realizzato il diagramma, rispondo meglio;)

Purtroppo i database relazionali attuali non supportano direttamente l'ereditarietà, quindi è necessario trasformarla in tabelle "semplici". Esistono generalmente 3 strategie per farlo:

  1. Tutte le classi 1 in un'unica tabella con campi non comuni in grado di abilitare NULL.
  2. Classi concrete 2 in tabelle separate. Le classi astratte non hanno le proprie tabelle.
  3. Tutte le classi in tabelle separate.

Per ulteriori informazioni su cosa significhi effettivamente e su alcuni pro e contro, vedere i collegamenti forniti nel mio post originale , ma in breve il (3) dovrebbe probabilmente essere il valore predefinito a meno che non si abbia un motivo specifico per uno degli altri due. È possibile rappresentare il (3) nel database semplicemente in questo modo:

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

Sfortunatamente, questa struttura ti permetterà di avere un personche non è né civilworker(cioè puoi istanziare la classe astratta), e ti permetterà anche di creare un personche sia entrambi civil e worker. Esistono modi per imporre il primo a livello di database e in un DBMS che supporta vincoli posticipati 3 anche quest'ultimo può essere imposto nel database, ma questo è uno dei pochi casi in cui l'uso dell'integrità a livello di applicazione potrebbe essere preferibile .


1 person , civile workerin questo caso.

2 civil e workerin questo caso ( personè "astratto").

3 Quale MySQL no.


In che modo è possibile applicare quest'ultimo in DBMS che supporta vincoli differiti? (impedendo a una persona di essere entrambi civile worker)
Gima,

@Gima Segui il link che ho fornito nella risposta.
Branko Dimitrijevic,

I database relazionali attuali non supportano l'ereditarietà. Che dire di postgresql? postgresql.org/docs/9.6/static/ddl-inherit.html
Climax,

@Climax Sono a conoscenza di PostgreSQL, ma la sua implementazione è solo parziale. Dal tuo link: "Altri tipi di vincoli (univoci, chiave primaria e vincoli di chiave esterna) non vengono ereditati".
Branko Dimitrijevic,

1
@naaz Esistono chiavi esterne in entrambi civile worker. Forse ti sei perso la sintassi della mano breve (solo REFERENCESsenza FOREIGN KEY)?
Branko Dimitrijevic

5

Non è necessario utilizzare Civil_ID e Worker_ID distinti; continua a utilizzare l'ID persona come chiave per tutte e tre le tabelle: Persona, Civile e Lavoratore. Aggiungi una colonna PersonType a Person con i due valori "Civil" e "Worker".

Ciò rappresenta ora le due sottoclassi CivilClass e WorkerClass della classe base astratta PersonClass come sottoentità Civil e Worker dell'entità base Person. Si ottiene una buona corrispondenza tra il modello di dati nel DB e il modello di oggetti nell'applicazione.


Ho fatto un sqlfiddle sqlfiddle.com/#!2/1f6a4/1 ma non so come unirmi ad altri tavoli, potresti per favore indicare la tua risposta qui in sqlfiddle?
cMinor

Non ci sono "distinti" civil_ide worker_id- sono la stessa cosa di person_id, appena nominati in modo diverso - guarda il FK1marcatore (chiave esterna) di fronte a loro.
Branko Dimitrijevic,

4

Il tuo caso è un'istanza di modellazione di classi / sottoclassi. Oppure, come hai rappresentato in ER, generalizzazione / specializzazione.

Esistono tre tecniche che ti aiuteranno a progettare tabelle mysql per coprire questo caso. Si chiamano Ereditarietà tabella singola, Ereditarietà tabella classi e Chiave primaria condivisa. Puoi leggerli nella scheda informativa dal tag corrispondente in SO.

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

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

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

L'ereditarietà a tabella singola è utile per casi semplici in cui la presenza di NULL non causa problemi. L'ereditarietà delle tabelle di classi è migliore per i casi più complicati. La chiave primaria condivisa è un buon modo per imporre relazioni uno a uno e per velocizzare i join.


1

È possibile creare una tabella dei tipi di persona e aggiungere un campo a tutte le tabelle che richiedono l'applicazione del tipo. Quindi creare chiavi esterne. Ecco un esempio derivante dal tuo ...

    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...
    );
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.