MySQL如何對兩個表的繼承建模
我有一些儲存數據的表,根據從事工作的人(工人/公民)的類型,我想將其儲存在
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' );
但是,有沒有辦法擺脫空值?
我的查詢是:
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。
既然我製作了圖表,我會更好地回答;)
不幸的是,目前的關係數據庫不直接支持繼承,因此您需要將其轉換為“普通”表。這樣做通常有3種策略:
- 單個表中的所有類1具有可以為 NULL 的非公共欄位。
- 具體等級2在單獨的表格中。抽像類沒有自己的表。
- 所有類在單獨的表中。
有關這實際上意味著什麼以及一些利弊的更多資訊,請參閱我的原始文章中提供的連結,但簡而言之,(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
既是又 是。有一些方法可以在數據庫級別強制執行前者,並且在支持延遲約束3的 DBMS 中,即使後者也可以在數據庫中強制執行,但這是使用應用程序級別完整性實際上可能更可取的少數情況之一.civil``worker
1
person
,在這種情況下civil
。worker
2
civil
,worker
在這種情況下(person
是“抽象的”)。3 MySQL 沒有。
不需要區分 Civil_ID 和 Worker_ID;只需繼續使用 Person-ID 作為所有三個表的鍵:Person、Civil 和 Worker。將列 PersonType 添加到具有兩個值“Civil”和“Worker”的 Person。
這現在將抽象基類 PersonClass 的兩個子類 CivilClass 和 WorkerClass 表示為基實體 Person 的子實體 Civil 和 Worker。您可以在 DB 中的數據模型與應用程序中的對像模型之間獲得很好的對應關係。