我想设计项目的数据模型,但我在“客户”部分遇到问题,因为我有两类客户:自然人和法人实体 哪种方式最好:
方法1 : 要有这样的3个表:
Customers:
ID int not null (PK)
CustomerType bit not null
NaturalPersonID int (FK)
LegalPersonID int (FK)
NaturalPeople:
ID int not null (PK)
FirstName nvarchar(50) not null
LastName nvarchar(50) not null
NationalSecurityNumber char(10) not null
...
LegalEntities:
ID int not null (PK)
CompanyName nvarchar(100) not null
RegistrationNumber char(20) not null
...
其中填充了NaturalPersonID或LegalPersonID,另一个为null,CustomerType显示客户类型(自然或法律)
方法2 : 要有一个包含所有字段的表:
ID int not null (PK)
CustomerType bit not null
FirstName nvarchar(50)
LastName nvarchar(50)
NationalSecurityNumber char(10)
CompanyName nvarchar(100)
RegistrationNumber char(20)
...
为每个客户填写一些字段,其他字段为空
方法3 : 要有一个包含某些字段的表:
ID int not null (PK)
CustomerType bit not null
FirstName nvarchar(50)
LastName nvarchar(100)
NationalSecurityNumber varchar(20)
...
自然地为自然客户填充哪些字段。但如果客户是合法客户,我们会逻辑地提供数据。例如,LastName字段中的CompanyName和NationalSecurityNumber字段中的RegistrationCode以及FirstName字段为空。
方法4 : 我没有想到的任何其他方式,你可以建议
P.S。我正在MS SQL Server 2012中实现我的数据库
答案 0 :(得分:7)
任何方法都有利弊,根据您的应用要求和分析,任何方法都适用。
顺便说一下,我更倾向于使用Method 1
进行一些考虑:
Customer
表将是NaturalPeople
和的基表
LegalEntities
,客户的主键将成为主键
其他两个。 避免对两个不同的商业价值使用字段,例如:
The fields are filled for the natural customers naturally. But if the customer is a Legal one, we put data logically. For example CompanyName in the LastName field and RegistrationCode in the NationalSecurityNumber field and the FirstName field is null.
由于违反first normal form,你很快就会因为没有将田地分开而受苦(想想看 如果National_Security_Number)是强制值 NaturalPeople和RegistrationCode是一个可选值 LegalEntities。您无法在该字段上设置唯一密钥或强制检查。
其他实体(如帐户,标志,地址......)将拥有 仅引用Customer表。
答案 1 :(得分:1)
在这种情况下,我通常会做一个表Customer
,它有一个PK和一个鉴别器列CustomerType
,还有两个详细表,一个用于Natural,一个用于Legal,但是这些附加表的主键与Customers
表的PK相同(类似于您的方法一,但没有两个子类型表的单独键)。这样查询就更简单了,你可以在master和detail之间强制执行1:0约束,没有代理键,数据也被标准化。
答案 2 :(得分:0)
简单说一句:不要忘记自然人和法人实体之间存在潜在的关系,自然人属于或代表法律实体。我会毫不犹豫地将LegalEntityID FK添加到NaturalPeople表中。
并且,为了简单起见,当指向“NaturalPeople”表时,我不会将外键字段“NaturalPersonID”命名为。称之为NaturalPeopleID,它会让事情更清晰。 “LegalPersonID”字段也是如此。您甚至可以将对象/表名称限制为“人员”和“实体”,或“人员”和“机构”(这是为了避免您的实体对象/表与关系数据库中的实体概念之间的任何混淆)。
答案 3 :(得分:0)
方法1是一种称为class-table-inheritance的设计模式。
方法2是一种称为single-table-inheritance的设计模式。
您可以通过访问标签并打开信息标签来阅读这些内容。
方法3有一个名字,目前我不知道。
在你的情况下,我会选择方法1。
在方法1中,您非常仔细地遵循了模式。我建议你考虑的一件事是共享主键。类表继承和共享主键很好地协同工作。
答案 4 :(得分:0)
create table party_type (
id serial primary key,
description text not null unique
);
insert into party_type ('description') values
('Organization'),
('Individual'),
('Automated Agent');
create table party (
id serial primary key,
party_type_id int not null references party_type(id),
organization_name text null,
last_name text null,
first_name text null,
);
insert into party (party_type_id, organization_name) values (1, 'Acme, Inc');
insert into party (party_type_id, last_name, first_name) values (2 'Doe', 'John');
create table role_type (
id serial primary key,
description text not null unique
);
insert into role_type ('description') values
('Customer'),
create table party_role (
party_id int not null references party(id),
role_type_id int not null references party_role_type(id),
primary key (party_id, role_type_id)
);
/* add both parties as customers: */
insert into party_role values (1, 1);
insert into party_role values (2, 1);
create table identifier_type (
id serial primary key,
description text not null unique
);
insert into identifier_type ('description') values
('Social Security Number'),
('Registration Number');
create table party_identifier (
party_id int not null references party(id),
identifier_type_id int not null references identifier_type(id),
id_number text not null,
primary key (party_id, identifier_type_id)
);
insert into party_identifier values
(1, 2, 'some company reg number'),
(2, 1, 'some ssn')