如何为两个表的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' );

但是,有没有一种方法可以消除空值?

我的查询是:

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


@cMinor-您正在问“如何知道从事这项工作的公民或工人的身份证?” 您实际上知道在现实生活中是谁做的(如果是家庭作业,则是假想的)?您是否有足够的源数据?

我已经习惯了继承,因此我创建了一个表人,该人将容纳人(工人,文职人员)的类型,然后在事件表中,如何根据工作(民事或工人)的方式来引用人?
cMinor

1
我相信您会在数据库管理员中获得更好的建议
Pieter Geerkens

Answers:


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既不是civilworker(即你可以实例化抽象类),并且还将让你创建一个person两个 civilworker有多种方法可以在数据库级别实施前者,并且在支持延迟约束的DBMS中3甚至后者也可以在数据库中实施,但这是少数几个使用应用程序级完整性可能更可取的情况之一。


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

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

3 MySQL没有。


后者如何在支持延迟约束的DBMS中实施?(禁止一个人同时成为civilworker
Gima

@Gima请点击我在答案中提供的链接。
布兰科·迪米特里耶维奇

您声称当前的关系数据库不支持继承。PostgreSQL呢?postgresql.org/docs/9.6/static/ddl-inherit.html
Climax

@Climax我知道PostgreSQL,但是它的实现只是部分的。通过您的链接:“不会继承其他类型的约束(唯一,主键和外键约束)。”
Branko Dimitrijevic

1
@naaz civil和中都存在外键worker。也许您错过了速记语法(只是REFERENCES不带FOREIGN KEY)?
Branko Dimitrijevic '18

5

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

现在,它代表抽象基类PersonClass的两个子类CivilClass和WorkerClass作为基本实体Person的子实体Civil和Worker。您将在数据库中的数据模型与应用程序中的对象模型之间找到很好的对应关系。


我已经完成了sqlfiddle sqlfiddle.com/#!2/1f6a4/1,但是我不知道如何连接其他表,能否在sqlfiddle中将您的答案指向此处?
cMinor

没有“区别”,civil_id并且worker_id-它们与相同person_id,只是名称有所不同-查看FK1它们前面的(外键)标记。
Branko Dimitrijevic 2013年

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...
    );
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.