Cara memodelkan pewarisan dua tabel MySQL

14

Saya memiliki beberapa tabel tempat saya menyimpan data dan tergantung pada tipe orang (pekerja, sipil) yang melakukan pekerjaan yang ingin saya simpan dalam sebuah eventtabel, sekarang orang-orang ini menyelamatkan seekor binatang (ada sebuah animalmeja).

Akhirnya, saya ingin memiliki meja untuk menyimpan acara bahwa seorang pria (pekerja, sipil), menyelamatkan seekor hewan, tetapi haluan haruskah saya menambahkan kunci asing atau bagaimana mengetahui idnilai sipil atau pekerja yang melakukan pekerjaan itu?

Sekarang, dalam desain ini saya tidak tahu bagaimana menghubungkan orang yang melakukan pekerjaan itu jika, saya hanya akan memiliki tipe orang (alias sipil). Saya hanya akan menyimpan civil_idlembah di personkolom di tabel terakhir ini ... tetapi bagaimana tahu kalau itu sipil atau pekerja, apakah saya perlu meja "perantara" lainnya?

Bagaimana cara merefleksikan desain diagram berikut ini di MySQL?

masukkan deskripsi gambar di sini

Detil tambahan

Saya telah memodelkannya dengan cara berikut:

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

Namun, apakah ada cara untuk menghilangkan nol?

Pertanyaan yang saya miliki adalah:

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 ;

Berikut adalah sqlfiddle yang diperbarui .

cMinor
sumber
apa tujuan tabel TYPE_PERSONketika hanya berisi satu kolom?
JW 웃
@cMinor - Anda bertanya "bagaimana cara mengetahui id sipil atau pekerja yang melakukan pekerjaan itu?" Apakah Anda benar-benar tahu siapa yang melakukan pekerjaan dalam kehidupan nyata (atau imajiner, apakah ini pekerjaan rumah)? Apakah Anda memiliki data sumber yang cukup?
Saya mulai terbiasa dengan warisan, jadi saya membuat meja orang yang akan menampung tipe orang (pekerja, sipil), kemudian di tabel acara, Bagaimana cara merujuk seseorang tergantung pada bagaimana pekerjaan (sipil atau pekerja)?
cMinor
1
Saya percaya Anda akan mendapatkan saran yang lebih baik dalam Administrator Database
Pieter Geerkens

Jawaban:

13

Karena saya membuat diagram, saya lebih baik menjawab;)

Sayangnya, basis data relasional saat ini tidak mendukung warisan secara langsung, oleh karena itu Anda perlu mengubahnya menjadi tabel "biasa". Secara umum ada 3 strategi untuk melakukannya:

  1. Semua kelas 1 dalam satu tabel dengan bidang non-umum yang dapat NULL.
  2. Kelas beton 2 dalam tabel terpisah. Kelas abstrak tidak memiliki tabel sendiri.
  3. Semua kelas dalam tabel terpisah.

Untuk lebih lanjut tentang apa arti sebenarnya ini dan beberapa pro dan kontra, silakan lihat tautan yang disediakan di posting asli saya , tetapi singkatnya (3) mungkin harus menjadi default Anda kecuali Anda memiliki alasan khusus untuk salah satu dari dua lainnya. Anda dapat mewakili (3) dalam database cukup seperti ini:

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

Sayangnya, struktur ini akan membiarkan Anda memiliki personyang bukan civilatau tidak worker(yaitu Anda dapat membuat instance kelas abstrak), dan juga akan membiarkan Anda membuat personyang keduanya civil dan worker. Ada cara untuk menegakkan yang pertama di tingkat basis data, dan dalam DBMS yang mendukung hambatan yang ditangguhkan 3 bahkan yang terakhir dapat ditegakkan di dalam basis data, tetapi ini adalah salah satu dari sedikit kasus di mana menggunakan integritas tingkat aplikasi mungkin sebenarnya lebih disukai .


1 person , civildan workerdalam hal ini.

2 civil dan workerdalam hal ini ( personbersifat "abstrak").

3 MySQL mana yang tidak.

Branko Dimitrijevic
sumber
Bagaimana yang terakhir dapat ditegakkan dalam DBMS yang mendukung kendala yang ditangguhkan? (melarang seseorang menjadi keduanya civildan worker)
Gima
@Gima Harap ikuti tautan yang saya berikan dalam jawaban.
Branko Dimitrijevic
Anda mengklaim basis data relasional saat ini tidak mendukung warisan. Bagaimana dengan postgresql? postgresql.org/docs/9.6/static/ddl-inherit.html
Climax
@ Climax Saya mengetahui PostgreSQL, tetapi implementasinya hanya parsial. Dari tautan Anda: "Jenis kendala lainnya (unik, kunci primer, dan batasan kunci asing) tidak diwariskan."
Branko Dimitrijevic
1
@naaz Kunci asing ada di keduanya civildan worker. Mungkin Anda melewatkan sintaks tangan pendek (hanya REFERENCEStanpa FOREIGN KEY)?
Branko Dimitrijevic
5

Tidak perlu untuk Civil_ID dan Worker_ID yang berbeda; terus gunakan Person-ID sebagai kunci untuk ketiga tabel: Person, Sipil, dan Pekerja. Tambahkan kolom PersonType ke Orang dengan dua nilai "Sipil" dan "Pekerja".

Ini sekarang mewakili dua sub-kelas CivilClass dan WorkerClass dari kelas dasar PersonClass sebagai sub-entitas Sipil dan Pekerja dari entitas entitas dasar. Anda mendapatkan korespondensi yang bagus antara model data dalam DB dengan model objek dalam aplikasi.

Pieter Geerkens
sumber
Saya telah melakukan sqlfiddle sqlfiddle.com/#!2/1f6a4/1 tapi saya tidak tahu bagaimana cara bergabung dengan tabel lain, dapatkah Anda mengarahkan jawaban Anda di sqlfiddle?
cMinor
Tidak ada "berbeda" civil_iddan worker_id- mereka adalah hal yang sama seperti person_id, hanya dinamai berbeda - lihat FK1penanda (kunci asing) di depan mereka.
Branko Dimitrijevic
4

Kasing Anda adalah turunan dari pemodelan kelas / subkelas. Atau, seperti yang telah Anda diagramkan di ER, generalisasi / spesialisasi.

Ada tiga teknik yang akan membantu Anda mendesain tabel mysql untuk membahas kasus ini. Mereka disebut Single Table Inheritance, Class Table Inheritance, dan Shared Primary key. Anda dapat membacanya di tab info dari tag terkait di SO.

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

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

/programming//tags/share-primary-key/info

Warisan tabel tunggal berguna untuk kasus-kasus sederhana di mana keberadaan NULLs tidak menyebabkan masalah. Warisan tabel kelas lebih baik untuk kasus yang lebih rumit. Kunci utama bersama adalah cara yang baik untuk menegakkan hubungan satu-ke-satu, dan untuk mempercepat bergabung.

Walter Mitty
sumber
1

Anda bisa membuat tabel tipe orang dan menambahkan bidang ke semua tabel yang membutuhkan penegakan tipe. Kemudian buat kunci asing. Berikut adalah contoh yang berasal dari Anda ...

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