วิธีสร้างแบบจำลองการสืบทอดของสองตาราง MySQL


14

ฉันมีตารางบางส่วนที่ฉันเก็บข้อมูลและขึ้นอยู่กับประเภทของบุคคล (คนงานพลเรือน) ที่ทำงานฉันต้องการเก็บไว้ในeventตารางตอนนี้พวกเหล่านี้ช่วยสัตว์ (มีanimalโต๊ะ)

ในที่สุดฉันต้องการโต๊ะเพื่อเก็บเหตุการณ์ที่ผู้ชาย (คนงานพลเรือน) ช่วยชีวิตสัตว์ แต่ฉันควรเพิ่มกุญแจต่างประเทศหรือคำนับให้รู้ถึงidคุณค่าของพลเรือนหรือคนงานที่ทำงานนั้นหรือไม่?

ตอนนี้ในการออกแบบนี้ฉันไม่ทราบวิธีการที่เกี่ยวข้องกับคนที่ทำงานถ้าฉันจะมีเพียงคนชนิด (พลเรือนหรือพลเรือน) ฉันจะเก็บcivil_idหุบเขาไว้ในpersonคอลัมน์ในตารางสุดท้ายนี้ แต่วิธีการ รู้ว่ามันเป็นทางแพ่งหรือคนงานฉันต้องการโต๊ะ "กลาง" อื่น ๆ หรือไม่?

จะสะท้อนการออกแบบไดอะแกรมต่อไปนี้ใน MySQL ได้อย่างไร?

ป้อนคำอธิบายรูปภาพที่นี่

รายละเอียดเพิ่มเติม

ฉันสร้างแบบจำลองด้วยวิธีต่อไปนี้:

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

อย่างไรก็ตามมีวิธีกำจัด nulls หรือไม่

คำถามที่ฉันมีคือ:

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 ;

นี่คือการปรับปรุง sqlfiddle


จุดประสงค์ของตารางคืออะไรTYPE_PERSONเมื่อมันมีเพียงหนึ่งคอลัมน์?
JW 웃

1
ติดตามเรื่องนี้: stackoverflow.com/questions/15128222/… ?

@cMinor - คุณกำลังถามว่า "จะรู้ id ของพลเรือนหรือคนงานที่ทำงานได้อย่างไร?" คุณรู้หรือไม่ว่าใครเป็นคนทำผลงานในชีวิตจริง (หรือในจินตนาการถ้าเป็นการบ้าน)? คุณมีแหล่งข้อมูลที่เพียงพอหรือไม่

ฉันเริ่มชินกับการสืบทอดดังนั้นฉันจึงสร้างคนบนโต๊ะที่จะเก็บประเภทของผู้คน (คนงานพลเรือน) จากนั้นในตารางเหตุการณ์วิธีการอ้างอิงบุคคลขึ้นอยู่กับงาน (พลเรือนหรือคนงาน) อย่างไร
cMinor

1
ฉันเชื่อว่าคุณจะได้รับคำแนะนำที่ดีขึ้นในผู้ดูแลระบบฐานข้อมูล
Pieter Geerkens

คำตอบ:


13

ตั้งแต่ฉันทำแผนภาพฉันตอบได้ดีกว่า;)

ฐานข้อมูลเชิงสัมพันธ์ในปัจจุบันน่าเสียดายที่ไม่รองรับการสืบทอดโดยตรงดังนั้นคุณต้องแปลงเป็นตาราง "ธรรมดา" โดยทั่วไปมี 3 กลยุทธ์ในการทำเช่นนี้:

  1. คลาส1ทั้งหมดในตารางเดียวที่มีเขตข้อมูลที่ไม่สามารถใช้ร่วมกันได้ NULL
  2. คลาสคอนกรีต2ในตารางแยกต่างหาก คลาสนามธรรมไม่มีตารางของตนเอง
  3. ชั้นเรียนทั้งหมดในตารางแยกต่างหาก

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับสิ่งนี้หมายถึงอะไรจริง ๆ และข้อดีและข้อเสียโปรดดูลิงก์ที่ให้ไว้ในโพสต์ต้นฉบับของฉันแต่โดยย่อ (3) น่าจะเป็นค่าเริ่มต้นของคุณเว้นแต่ว่าคุณมีเหตุผลเฉพาะสำหรับอีกสองข้อ คุณสามารถแสดง (3) ในฐานข้อมูลแบบนี้:

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

แต่น่าเสียดายที่โครงสร้างนี้จะช่วยให้คุณมีpersonที่เป็นค่าcivilมิได้worker(เช่นคุณสามารถยกตัวอย่างระดับนามธรรม) และยังจะช่วยให้คุณสร้างpersonที่เป็นทั้งสอง และcivil มีวิธีการบังคับใช้แบบเก่าที่ระดับฐานข้อมูลและใน DBMS ที่สนับสนุนข้อ จำกัด ที่เลื่อนออกไป3แม้จะสามารถบังคับใช้แบบหลังในฐานข้อมูลได้ แต่นี่เป็นหนึ่งในไม่กี่กรณีที่การใช้ความสมบูรณ์ระดับแอปพลิเคชันอาจจะดีกว่า .worker


1 person , civilและworkerในกรณีนี้

2 civilและworkerในกรณีนี้ ( personคือ "นามธรรม")

3ซึ่ง MySQL ไม่ได้


วิธีหลังสามารถบังคับใช้ใน DBMS ที่สนับสนุนข้อ จำกัด รอการตัดบัญชีได้อย่างไร (ไม่อนุญาตให้บุคคลเป็นทั้งคู่civilและworker)
Gima

@Gima โปรดติดตามลิงก์ที่ฉันให้ไว้ในคำตอบ
Branko Dimitrijevic

คุณอ้างว่าฐานข้อมูลเชิงสัมพันธ์ปัจจุบันไม่สนับสนุนการสืบทอด แล้ว postgresql ล่ะ? postgresql.org/docs/9.6/static/ddl-inherit.html
Climax

@ Climax ฉันทราบเกี่ยวกับ PostgreSQL แต่การนำไปใช้นั้นเป็นเพียงบางส่วนเท่านั้น จากลิงก์ของคุณ: "ข้อ จำกัด ประเภทอื่น ๆ (ไม่ซ้ำ, คีย์หลักและข้อ จำกัด คีย์ต่างประเทศ) ไม่ได้รับการสืบทอด"
Branko Dimitrijevic

1
คีย์ @naaz ต่างประเทศที่มีอยู่ทั้งในและcivil workerบางทีคุณอาจพลาดไวยากรณ์สั้น ๆ ( REFERENCESโดยไม่มีFOREIGN KEY)?
Branko Dimitrijevic

5

ไม่จำเป็นต้องใช้ Civil_ID และ Worker_ID ที่แตกต่างกัน เพียงแค่ใช้ Person-ID ต่อไปเป็นกุญแจสำคัญสำหรับทั้งสามตาราง: Person, Civil และ Worker เพิ่มคอลัมน์ PersonType ให้กับบุคคลที่มีสองค่า "Civil" และ "Worker"

ตอนนี้แสดงถึงสองคลาสย่อย CivilClass และ WorkerClass ของคลาสฐานนามธรรม PersonClass เป็น sub-entity Civil และ Worker ของเอนทิตีฐานบุคคล คุณจะได้รับการติดต่อที่ดีระหว่างตัวแบบข้อมูลในฐานข้อมูลด้วยตัวแบบวัตถุในแอปพลิเคชัน


ฉันได้ทำ sqlfiddle sqlfiddle.com/#!2/1f6a4/1 แล้วแต่ฉันไม่ทราบวิธีเข้าร่วมตารางอื่น ๆ คุณช่วยชี้คำตอบของคุณที่นี่ใน sqlfiddle ได้ไหม?
cMinor

ไม่มี "ชัดเจน" civil_idและworker_id- พวกเขาเป็นสิ่งเดียวกันเป็นperson_idเพียงชื่อที่แตกต่างกัน - ดูที่เครื่องหมายFK1(คีย์ต่างประเทศ) ที่ด้านหน้าของพวกเขา
Branko Dimitrijevic

4

กรณีของคุณเป็นตัวอย่างของการสร้างแบบจำลองคลาส / คลาสย่อย หรือตามที่คุณไดอะแกรมใน ER การวางนัย / ความเชี่ยวชาญ

มีสามเทคนิคที่จะช่วยคุณออกแบบตาราง mysql เพื่อครอบคลุมกรณีนี้ พวกเขาจะเรียกว่าสืบทอดตารางเดียว, สืบทอดตารางระดับและคีย์หลักที่ใช้ร่วมกัน คุณสามารถอ่านพวกมันได้ในแท็บข้อมูลจากแท็กที่เกี่ยวข้องใน SO

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

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

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

การสืบทอดตารางเดี่ยวมีประโยชน์สำหรับกรณีง่าย ๆ ที่การมี NULL ไม่ทำให้เกิดปัญหา การสืบทอดตารางคลาสจะดีกว่าสำหรับกรณีที่ซับซ้อนมากขึ้น คีย์หลักที่ใช้ร่วมกันเป็นวิธีที่ดีในการบังคับใช้ความสัมพันธ์แบบหนึ่งต่อหนึ่งและเพื่อเพิ่มความเร็วในการเข้าร่วม


1

คุณสามารถสร้างตารางประเภทบุคคลและเพิ่มเขตข้อมูลลงในตารางทั้งหมดที่ต้องการการบังคับประเภท จากนั้นสร้างคีย์ต่างประเทศ นี่คือตัวอย่างที่ได้มาจากคุณ ...

    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...
    );
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.