数据库模型中的分类
Categorisation in database models
我有一个关系数据库,我想在其中有一个table 'Entity'。这个实体有一个类型:它可以是个人、公司或非营利组织。根据此类型,它应该具有不同的属性(列):
Person:
- id
- name
- age
- statuses: ['child', 'adult', 'senior']
Company:
- id
- name
- address
- contact_form
- industry
- statuses: ['startup', 'scaleup', 'corporate']
NonProfit:
- id
- name
- address
- bank_account
- statuses: ['environmental', 'social']
它们都有一个名字,在前端它们应该以类似的方式出现在列表中:
Entities:
Name Type Status
----------------------------------
Mary Person Adult
Mcenroe Company Startup
Joe Person Child
BetterWorld NonProfit Social
如果您随后单击详细信息,实体将以不同的方式显示,具体取决于类型。
我要创建 4 个不同的 table:Entity、Person、Company 和 NonProfit,然后在 Entity table 中引用后三个中的任何一个。
Entity:
- id
- person_id #optional
- company_id #optional
- nonprofit_id #optional
然后以某种方式强制该实体只有三个外键之一。但感觉笨重,所以我认为有更好的方法。不过我不太了解关系数据库。
在关系数据库中启用此类数据的最佳方法是什么?
您最好使用单个 table 并检查约束:
create table entities (
entityid . . .,
name varchar(255),
type varchar(255),
status varchar(255),
age int,
. . . -- remaining columns
check (type in ('Person', 'Company', 'Nonprofit'))
check (type = 'Person' and status in ('child', 'adult', 'senior') or
type = 'Company' and status in ('startup', 'scaleup', 'corporate') or
type = 'Nonprofit' and status in ('environmental', 'social')
),
check (age is null or type = 'Person'),
. . . -- remaining check constraints
);
SQL 不擅长这些“一对一”关系。这为您带来的是与实体建立外键关系的能力,无论类型如何。
如果将数据拆分为三个单独的 table,您将失去拥有此类外键关系的能力。
一个两全其美的替代方案是四个 table,一个 entities
table 和另外三个 table,每种类型一个.额外的 table 和 entity
table 可以共享同一个主键。但是,在这种情况下,您有一些特定于类型的关键重叠列,因此即使这样也会有点混乱。例如,如果您将状态存储在 table 类型中,您的实体查询将如下所示:
select e.*, coalesce(p.status, c.status, e.status)
from entities e left join
persons p
on e.entity_id = p.person_id left join
companies c
on e.entity_id = c.company_id left join
nonprofits n
on e.entity_id = e.nonprofit_id;
与所有这些 check
约束相比,这似乎有点混乱。
如果要求有一个公共实体来显示来自三个实体的数据,那么结合来自所有三个实体的数据的视图怎么样-> Person/NonProfit/Company 如下所示。我假设个人和公司之间没有任何关系,除了它们只是您的数据模型中的两个实体之外。
create view all_entites
as
select name,'Person' as entity,status
from Person
union all
select name,'Company' as entity,status
from Company
union all
select name,'NonProfit' as entity,status
from NonProfit
我有一个关系数据库,我想在其中有一个table 'Entity'。这个实体有一个类型:它可以是个人、公司或非营利组织。根据此类型,它应该具有不同的属性(列):
Person:
- id
- name
- age
- statuses: ['child', 'adult', 'senior']
Company:
- id
- name
- address
- contact_form
- industry
- statuses: ['startup', 'scaleup', 'corporate']
NonProfit:
- id
- name
- address
- bank_account
- statuses: ['environmental', 'social']
它们都有一个名字,在前端它们应该以类似的方式出现在列表中:
Entities:
Name Type Status
----------------------------------
Mary Person Adult
Mcenroe Company Startup
Joe Person Child
BetterWorld NonProfit Social
如果您随后单击详细信息,实体将以不同的方式显示,具体取决于类型。
我要创建 4 个不同的 table:Entity、Person、Company 和 NonProfit,然后在 Entity table 中引用后三个中的任何一个。
Entity:
- id
- person_id #optional
- company_id #optional
- nonprofit_id #optional
然后以某种方式强制该实体只有三个外键之一。但感觉笨重,所以我认为有更好的方法。不过我不太了解关系数据库。
在关系数据库中启用此类数据的最佳方法是什么?
您最好使用单个 table 并检查约束:
create table entities (
entityid . . .,
name varchar(255),
type varchar(255),
status varchar(255),
age int,
. . . -- remaining columns
check (type in ('Person', 'Company', 'Nonprofit'))
check (type = 'Person' and status in ('child', 'adult', 'senior') or
type = 'Company' and status in ('startup', 'scaleup', 'corporate') or
type = 'Nonprofit' and status in ('environmental', 'social')
),
check (age is null or type = 'Person'),
. . . -- remaining check constraints
);
SQL 不擅长这些“一对一”关系。这为您带来的是与实体建立外键关系的能力,无论类型如何。
如果将数据拆分为三个单独的 table,您将失去拥有此类外键关系的能力。
一个两全其美的替代方案是四个 table,一个 entities
table 和另外三个 table,每种类型一个.额外的 table 和 entity
table 可以共享同一个主键。但是,在这种情况下,您有一些特定于类型的关键重叠列,因此即使这样也会有点混乱。例如,如果您将状态存储在 table 类型中,您的实体查询将如下所示:
select e.*, coalesce(p.status, c.status, e.status)
from entities e left join
persons p
on e.entity_id = p.person_id left join
companies c
on e.entity_id = c.company_id left join
nonprofits n
on e.entity_id = e.nonprofit_id;
与所有这些 check
约束相比,这似乎有点混乱。
如果要求有一个公共实体来显示来自三个实体的数据,那么结合来自所有三个实体的数据的视图怎么样-> Person/NonProfit/Company 如下所示。我假设个人和公司之间没有任何关系,除了它们只是您的数据模型中的两个实体之外。
create view all_entites
as
select name,'Person' as entity,status
from Person
union all
select name,'Company' as entity,status
from Company
union all
select name,'NonProfit' as entity,status
from NonProfit