谢谢你的关注。自从我在学校和大学学习规范化以来,已经有一段时间了,如果你在这个行业工作,你会发现这些理论上的东西往往会干扰你老板告诉你的事情。所以这里有一个我正在思考的东西的例子,我很想听听你的意见。我甚至不确定这种方法是对还是错,所以每个答案都是受欢迎的。
方案: 我们正在开发人员管理系统(PMS)。为此,我们有一个Person表,用于存储关于每个人的通用信息(例如姓名),Country表,用于存储人的本地国家和用于人种的Race表。
因此,你可以在Person上有两个外键列,链接到Country和Race,对吧?
然而,我的老板想要我使用第四张桌子。让我们称之为PersonType。 PersonType由主键以及Country和Race的外键列组成。然后Person表只有一个到PersonType的外键列。
因此,Person和PersonType之间会有n:1关系,PersonType和Country / Race之间会有n:1关系,对吗?
在我看来,PersonType表不是必需的,因为你可以直接将外键列放在Person表上,但是我的老板认为PersonType可以用来约束哪些Country / Race组合是有效的。我理解这个论点,但我问自己这个数据库是否仍然正确归一化。
(当然我们并没有真正开发PMS,但我认为很容易想象,我不能谈论由于NDA而我们正在开发的内容)。
更新2016年10月21日
以抽象的方式表示表结构的样子:
table person_v1(
person_id int primarykey,
name string,
country_id int foreignkey(country),
race_id int foreignkey(race)
)
table person_v2(
person_id int primarykey,
name string,
person_type_id int foreignkey(person_type)
)
table person_type(
person_type_id int primarykey,
country_id int foreignkey(country),
race_id int foreignkey(race)
)
table country(
country_id int primarykey,
name string
)
table race(
race_id int primarykey,
name string
)
感谢您到目前为止的答案
答案 0 :(得分:1)
1:N或M:N关系的数量不能确定关系的正常形式。这个问题实际上与规范化无关。
一些表格。 。 。
您的设计
尽可能遵循标准。 对于国家/地区,我将遵循ISO 3166-1。
create table countries (
iso_country_code char(3) primary key,
country_name varchar(75) not null unique
);
insert into countries (iso_country_code, country_name) values
('USA', 'United States of America'),
('GBR', 'United Kingdom of Great Britain and Northern Ireland'),
('MKD', 'Macedonia (the former Yugoslav Republic of)'),
('ZZZ', 'Unknown country'); -- 'ZZZ' is reserved for a user-assigned value.
对于比赛,我将遵循CDC / HL7比赛代码。 还有其他标准。 其中一个可能更合适。 见http://www.cdc.gov/nchs/data/dvs/race_ethnicity_codeset.pdf
大多数应用程序允许每个人使用多个竞赛代码。 我忽略了这个问题的真实事实。
create table races (
cdc_unique_id char(6) primary key,
cdc_race_concept varchar(50) not null unique
);
insert into races (cdc_unique_id, cdc_race_concept) values
('2056-0', 'Black'),
('2106-3', 'White'),
('2076-8', 'Native Hawaiian or other Pacific islander'),
('zzzz-z', 'Unknown');
create table persons (
person_id integer primary key,
person_full_name varchar(25) not null,
iso_country_code char(2) not null
default 'ZZZ'
references countries (iso_country_code)
on update cascade
on delete set default,
cdc_unique_id char(6) not null
default 'zzzz-z'
references races (cdc_unique_id)
on update cascade
on delete set default
);
这三张表中至少有5NF。
您的设计存在一个潜在问题 是它允许任意的配对 国家和种族。 想象一下,而不是国家和种族, 我们在谈论美国的城市和州。 任意削减城市和国家都是允许的 "旧金山,AL"。 但是没有一个名为" San Francisco"在阿拉巴马州。
这就是为什么允许任意对决可能是一个糟糕的决定。
老板的设计
-- The same as the table above.
create table countries (
iso_country_code char(3) primary key,
country_name varchar(75) not null unique
);
insert into countries (iso_country_code, country_name) values
('USA', 'United States of America'),
('GBR', 'United Kingdom of Great Britain and Northern Ireland'),
('MKD', 'Macedonia (the former Yugoslav Republic of)'),
('ZZZ', 'Unknown country'); -- 'ZZZ' is reserved for a user-assigned value.
-- Also the same as the table above.
create table races (
cdc_unique_id char(6) primary key,
cdc_race_concept varchar(50) not null unique
);
insert into races (cdc_unique_id, cdc_race_concept) values
('2056-0', 'Black'),
('2106-3', 'White'),
('2076-8', 'Native Hawaiian or other Pacific islander'),
('zzzz-z', 'Unknown');
-- This table is new.
create table person_types (
iso_country_code char(3) not null
default 'ZZZ'
references countries (iso_country_code)
on update cascade
on delete set default,
cdc_unique_id char(6) not null
default 'zzzz-z'
references races (cdc_unique_id)
on update cascade
on delete set default,
primary key (iso_country_code, cdc_unique_id)
);
insert into person_types values
('USA', '2016-3'),
('USA', '2056-0'),
('GBR', '2016-3'),
('GBR', '2056-0'),
这个" person_types"表记录了一个事实 您的数据库设计没有。 它记录了这个事实 白人和黑人 可能是美国和英国本土的。 如果记录这一事实很重要,那么必须包含" person_types"。
此外,值得注意的是,此表不受其他评论中引用的问题的影响;你不能重复添加iso_country_code和cdc_unique_id都为空(not null
约束)的行,你不能复制iso_country_code和cdc_unique_id(primary key
约束)等等。
从概念上讲,您可以在规范化之前决定存储哪些事实。规范化可以帮助您处理模式中不存在的属性。这是一个不同的数据库设计任务。
-- Structurally identical to the table above.
-- Constraints are slightly different.
--
create table persons (
person_id integer primary key,
person_full_name varchar(25) not null,
iso_country_code char(2) not null
default 'ZZZ',
cdc_unique_id char(6) not null
default 'zzzz-z',
constraint person_types_fk foreign key (iso_country_code, cdc_unique_id)
references person_types (iso_country_code, cdc_unique_id)
on update cascade
on delete set default
);
所有这四个表至少都是5NF。
不同之处在于,一组表格比另一组更规范化。
不同之处在于一组表记录了另一组不的事实。
答案 1 :(得分:0)
我们假设这个表对你和你老板的设计都很常见:
CREATE TABLE RaceMeetings
( country_name VARCHAR(30) NOT NULL,
race_name VARCHAR(25) NOT NULL,
UNIQUE ( country_name, race_name ) );
据我所知,你的设计是这样的(一张桌子):
CREATE TABLE People_v1
( person_name VARCHAR(35) NOT NULL UNIQUE,
country_name VARCHAR(30) NOT NULL,
race_name VARCHAR(25) NOT NULL,
FOREIGN KEY ( country_name, race_name )
REFERENCES RaceMeetings ( country_name, race_name ) );
...而你老板的设计就是这个(两张桌子):
CREATE TABLE People_v2
( person_name VARCHAR(35) NOT NULL UNIQUE );
CREATE TABLE RaceMeetingAttendance
( person_name VARCHAR(35) NOT NULL UNIQUE
REFERENCES People_v2 ( person_name ),
country_name VARCHAR(30) NOT NULL,
race_name VARCHAR(25) NOT NULL,
FOREIGN KEY ( country_name, race_name )
REFERENCES RaceMeetings ( country_name, race_name ) );
两种设计
RaceMeetings
中定义一个人。你老板的设计另外还有6NF,但这并不一定会带来任何实际优势。
但是,我确实更喜欢你的老板根据经验法则设计表格应该是实体或实体之间的关系,而不是两者。换句话说,比赛会议如“比赛'太平洋大奖赛'在日本举行”并不会让我觉得这是一个人的属性。在我看来,这更像是一种关系(从人到种族会议的通信),并使用一个单独的表来模拟这种关系,这使我可以有用地给它命名为'RaceMeetingAttendance'。
也就是说,您的设计的优势在于,如果需要,未参加比赛的人不能存在于您的数据库中。