MySQL如何对两个表的继承进行建模

edg*_*tze 20 mysql database-design subtypes

我有一些表格来存储数据,并且根据从事工作的人(工人/文职人员)的类型,我想将其存储在event表格中,现在这些人拯救了一只动物(有一张animal桌子)。

最后,我想要一个表来存储一个人(工人/平民)拯救动物的事件,但是我应该如何添加外键或如何知道id完成这项工作的平民或工人的价值?

现在,在这个设计中,我不知道如何关联哪个人完成了这项工作,如果我只有一种人(又名平民)我只会将civil_idvale存储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' );
Run Code Online (Sandbox Code Playgroud)

但是,有没有办法摆脱空值?

我的疑问是:

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 ;
Run Code Online (Sandbox Code Playgroud)

这是更新的sqlfiddle

Bra*_*vic 18

既然我做了图表,我最好回答;)

不幸的是,当前的关系数据库不直接支持继承,因此您需要将其转换为“普通”表。这样做通常有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...
);
Run Code Online (Sandbox Code Playgroud)

不幸的是,这种结构可以让你有一个person既不是civilworker(即你可以实例化抽象类),并且还将让你创建一个person两个 civilworker有一些方法可以在数据库级别强制执行前者,在支持延迟约束3的 DBMS 中,甚至可以在数据库中强制执行后者,但这是使用应用程序级别完整性实际上可能更可取的少数情况之一.


1 personcivil并且worker在这种情况下。

2 civilworker在这种情况下(person是“抽象的”)。

3 MySQL 没有。

  • 您声称当前的关系数据库不支持继承。那么 postgresql 呢?https://www.postgresql.org/docs/9.6/static/ddl-inherit.html (2认同)

Pie*_*ens 10

不需要不同的 Civil_ID 和 Worker_ID;只需继续使用 Person-ID 作为所有三个表的键:Person、Civil 和 Worker。将列 PersonType 添加到具有两个值“Civil”和“Worker”的 Person。

这现在将抽象基类 PersonClass 的两个子类 CivilClass 和 WorkerClass 表示为基实体 Person 的子实体 Civil 和 Worker。您可以在 DB 中的数据模型与应用程序中的对象模型之间获得很好的对应关系。


Wal*_*tty 5

您的案例是类/子类建模的一个实例。或者,正如您在 ER 中绘制的那样,泛化/专业化。

有三种技术可以帮助您设计 mysql 表来涵盖这种情况。它们被称为单表继承、类表继承和共享主键。您可以在 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

单表继承对于存在 NULL 不会导致问题的简单情况很有用。类表继承更适合更复杂的情况。共享主键是强制执行一对一关系和加速连接的好方法。