数据库规范化混乱?
Database Normalization confusion?
我有 5 张桌子:
- tbl省
- tblDivison
- tbl地区
- tblCity
- tbl选区
tblProvince
:
- ID
- 姓名
- 面积
TblDivision
:
- ID
- 姓名
- 面积
- Province_id
tblDistrict
:
- ID
- 姓名
- 面积
- Province_id
- Division_id
tblCity
:
- ID
- 姓名
- 面积
- Province_id
- Division_id
- District_id
TblConstituency
:
- ID
- 姓名
- 面积
- Province_id
- Division_id
- District_id
- City_id
这是存储数据的正确方法吗?添加该区域的完整详细信息。
或者我应该只保存上一个区域的id(比如城市是选区的容器)。要存储选区的详细信息,我应该用它添加 city_id。
像这样...
tblCity
+-------------+
| ID |
+-------------+
| Name |
+-------------+
| Area |
+-------------+
| District_id |
+-------------+
TblConstituency
+-------------+
| ID |
+-------------+
| Name |
+-------------+
| Area |
+-------------+
| City_id |
+-------------+
如果我想获得关于选区的完整详细信息,我可以获得城市的 ID,从城市我可以得到地区,从地区我可以获得分区等等。
但是,我觉得这是一个巨大的矫枉过正。每次我需要获取详细信息时,这将是一个很长的查询。
那么,最好的方法是什么?
P.S:很抱歉描述我的问题的方式不佳。
切勿将相同的信息存储两次。这意味着您将不得不手动保持信息同步,而同步是困难且容易出错的。基本上,任何时候你有多个真相来源,你的真相来源为零。
考虑一下您的 table:
Division
+-------------+
| ID |
+-------------+
| Name |
+-------------+
| Area |
+-------------+
| Province_id |
+-------------+
District
+-------------+
| ID |
+-------------+
| Name |
+-------------+
| Area |
+-------------+
| Province_id |
+-------------+
| Division_id |
+-------------+
Division
已经在存储 Province_id
。那么为什么 District
也需要存储它呢?如果 District
存储的 与对应的 Division
记录不同 Province_id
会怎样?哪个 District
是正确的?
只需link到直接父记录:
District
+-------------+
| ID |
+-------------+
| Name |
+-------------+
| Area |
+-------------+
| Division_id |
+-------------+
Division
table的相关信息已经存在,可以查询。 (基本上,这就是 JOIN
关键字的作用。)由于您已经掌握了信息,因此无需重复。
并且只是为了澄清其他答案并删除冗余,这可能会与相应的 query/joins 一起澄清。我正在重命名列以确保上下文得到澄清,但可能缺少 "Area" 字段
的上下文
tblProvince: ( ID, ProvinceName, Area )
TblDivision: ( ID, DivisionName, ProvinceID )
tblDistrict: ( ID, DistrictName, DivisionID )
tblCity: ( ID, CityName, DistrictID )
TblConstituency: ( ID, ConstituencyName, CityID )
select
Con.ConstituencyName,
City.CityName,
Dis.DistrictName,
Div.DivisionName,
Prov.ProvinceName,
Prov.Area
from
tblConstituency Con
JOIN tblCity City
on Con.CityID = City.ID
JOIN tblDistrict Dis
on City.DistrictID = Dis.ID
JOIN tblDivision Div
on Dis.DivisionID = Div.ID
JOIN tblProvince Prov
on Div.ProvinceID = Prov.ID
并注意从一个 table 到下一个的 JOINS 的分层表示。您会看到 table 的直接相关性。然后,如果您正在寻找有问题的特定区域,只需应用 WHERE 子句。
通过 BCNF 的规范化基于函数依赖性。什么
数据中的函数依赖是这样的吗?什么是
候选键?
Cities
State County City
--
Alabama Pike Troy
Arkansas Pike Delight
Florida Bay Springfield
Maine Penobscot Springfield
这里只有一个(微不足道的)函数依赖而且只有一个
候选键。唯一的 FD 是 State, County, City -> State, County,
城市。唯一的候选键是 {State, County, City}。这种关系
至少为 5NF。
你不能改善这种关系,但你可以改善
数据库。数据库不知道没有名为“Los”的县
Angeles”在阿拉巴马州。所以它会让你插入这个无效的行。
Cities
State County City
--
Alabama Los Angeles Troy
要修复 那个 问题,请添加一个包含所有有效
县,并设置外键引用。
Counties
State
--
Alabama Autauga
Alabama Baldwin
...
Alabama Pike
...
California Los Angeles
...
关系"Counties"都是键,没有非素数
属性。 "Counties" 也至少在 5NF。
数据库仍然不知道它不应该允许这样的行。
Cities
State County City
--
Wales Pike Troy
美国没有名为 威尔士 的州。同样解决这个问题
方法作为最后一个问题。
States
--
Alabama
Arkansas
...
California
...
并设置从县到州的外键引用。
这是标准 SQL 中的样子,只是我没有
供应所有 50 个州或所有 3000 多个县。
create table states (
state varchar(100) primary key
);
insert into states values
('Alabama'), ('Arkansas'), ('California'), ('Florida'),
('Maine'); -- and more . . .
create table counties (
county varchar(100) not null,
state varchar(100) not null,
primary key (county, state),
foreign key (state) references states (state)
on update restrict on delete restrict
);
insert into counties values
('Autauga', 'Alabama'), ('Baldwin', 'Alabama'), ('Pike', 'Alabama'),
('Pike', 'Arkansas'),
('Los Angeles', 'California'),
('Bay', 'Florida'),
('Penobscot', 'Maine'); -- and more . . .
create table cities (
city varchar(100) not null,
county varchar(100) not null,
state varchar(100) not null,
primary key (city, county, state),
foreign key (county, state) references counties (county, state)
on update restrict on delete restrict
);
insert into cities values
('Troy', 'Pike', 'Alabama'),
('Delight', 'Pike', 'Arkansas'),
('Springfield', 'Penobscot', 'Maine'),
('Springfield', 'Bay', 'Florida'); -- and more . . .
现在你会发现无法插入无效的元组
{特洛伊,洛杉矶,阿拉巴马}和{特洛伊,派克,威尔士}。
使用代理 ID 号代替自然键不会改变
正常形式。但它确实 改变了数据库的工作方式。并不是
一定是好的。
使用上面的 SQL 表,此更新将失败。
update states
set state = 'Wibble'
where state = 'Alabama';
这是一件好事。
让我们用代理 ID 号来构建这些表。
create table states (
state_id integer primary key,
state varchar(100) not null unique
);
insert into states values
(1, 'Alabama'), (2, 'Arkansas'), (3, 'California'), (4, 'Florida'),
(5, 'Maine'); -- and more . . .
create table counties (
county_id integer not null,
county varchar(100) not null,
state_id integer not null,
foreign key (state_id) references states (state_id)
on update restrict on delete restrict,
primary key (county_id, state_id),
unique (county, state_id)
);
insert into counties values
(1, 'Autauga', 1), (2, 'Baldwin', 1), (3, 'Pike', 1),
(4, 'Pike', 2),
(5, 'Los Angeles', 3),
(6, 'Bay', 4),
(7, 'Penobscot', 5); -- and more . . .
create table cities (
city_id integer not null,
city varchar(100) not null,
county_id integer not null,
state_id integer not null,
foreign key (county_id, state_id) references counties (county_id, state_id)
on update restrict on delete restrict,
primary key (city_id, county_id, state_id),
unique (city, county_id, state_id)
);
insert into cities values
(1, 'Troy', 3, 1),
(2, 'Delight', 4, 2),
(3, 'Springfield', 7, 5),
(4, 'Springfield', 6, 4); -- and more . . .
所有这三个表至少仍处于 5NF 状态。但是这个
(无效)更新现在将成功。
update states
set state = 'Wibble'
where state = 'Alabama';
这是一件坏事。
使用代理 ID 号使每个外键引用
具有与声明它们相同的行为 on update cascade
。恢复
on update restrict
的部分语义,你必须取
撤销更新权限的额外的、不直观的步骤
参考表。
几乎没有人能正确理解这一部分。
没有实际原则可以证明拆分主键是合理的
为了有一条你可以遵循的路径来恢复原来的路径
关系。换句话说,没有 relational 原则
证明改变这个...
Cities
city_id city county_id state_id
--
1 Troy 3 2
...至此。
Cities
city_id city county_id
--
1 Troy 3
Counties
county_id county state_id
--
3 Pike 1
不仅没有关系原则可以证明分裂
主键,它 创建 关系模型的问题之一
旨在解决的数据。查找"IMS",一个分层数据库
管理系统,要求用户遵循路径
数据文件。
我有 5 张桌子:
- tbl省
- tblDivison
- tbl地区
- tblCity
- tbl选区
tblProvince
:
- ID
- 姓名
- 面积
TblDivision
:
- ID
- 姓名
- 面积
- Province_id
tblDistrict
:
- ID
- 姓名
- 面积
- Province_id
- Division_id
tblCity
:
- ID
- 姓名
- 面积
- Province_id
- Division_id
- District_id
TblConstituency
:
- ID
- 姓名
- 面积
- Province_id
- Division_id
- District_id
- City_id
这是存储数据的正确方法吗?添加该区域的完整详细信息。
或者我应该只保存上一个区域的id(比如城市是选区的容器)。要存储选区的详细信息,我应该用它添加 city_id。
像这样...
tblCity
+-------------+
| ID |
+-------------+
| Name |
+-------------+
| Area |
+-------------+
| District_id |
+-------------+
TblConstituency
+-------------+
| ID |
+-------------+
| Name |
+-------------+
| Area |
+-------------+
| City_id |
+-------------+
如果我想获得关于选区的完整详细信息,我可以获得城市的 ID,从城市我可以得到地区,从地区我可以获得分区等等。
但是,我觉得这是一个巨大的矫枉过正。每次我需要获取详细信息时,这将是一个很长的查询。
那么,最好的方法是什么?
P.S:很抱歉描述我的问题的方式不佳。
切勿将相同的信息存储两次。这意味着您将不得不手动保持信息同步,而同步是困难且容易出错的。基本上,任何时候你有多个真相来源,你的真相来源为零。
考虑一下您的 table:
Division
+-------------+
| ID |
+-------------+
| Name |
+-------------+
| Area |
+-------------+
| Province_id |
+-------------+
District
+-------------+
| ID |
+-------------+
| Name |
+-------------+
| Area |
+-------------+
| Province_id |
+-------------+
| Division_id |
+-------------+
Division
已经在存储 Province_id
。那么为什么 District
也需要存储它呢?如果 District
存储的 与对应的 Division
记录不同 Province_id
会怎样?哪个 District
是正确的?
只需link到直接父记录:
District
+-------------+
| ID |
+-------------+
| Name |
+-------------+
| Area |
+-------------+
| Division_id |
+-------------+
Division
table的相关信息已经存在,可以查询。 (基本上,这就是 JOIN
关键字的作用。)由于您已经掌握了信息,因此无需重复。
并且只是为了澄清其他答案并删除冗余,这可能会与相应的 query/joins 一起澄清。我正在重命名列以确保上下文得到澄清,但可能缺少 "Area" 字段
的上下文tblProvince: ( ID, ProvinceName, Area )
TblDivision: ( ID, DivisionName, ProvinceID )
tblDistrict: ( ID, DistrictName, DivisionID )
tblCity: ( ID, CityName, DistrictID )
TblConstituency: ( ID, ConstituencyName, CityID )
select
Con.ConstituencyName,
City.CityName,
Dis.DistrictName,
Div.DivisionName,
Prov.ProvinceName,
Prov.Area
from
tblConstituency Con
JOIN tblCity City
on Con.CityID = City.ID
JOIN tblDistrict Dis
on City.DistrictID = Dis.ID
JOIN tblDivision Div
on Dis.DivisionID = Div.ID
JOIN tblProvince Prov
on Div.ProvinceID = Prov.ID
并注意从一个 table 到下一个的 JOINS 的分层表示。您会看到 table 的直接相关性。然后,如果您正在寻找有问题的特定区域,只需应用 WHERE 子句。
通过 BCNF 的规范化基于函数依赖性。什么 数据中的函数依赖是这样的吗?什么是 候选键?
Cities State County City -- Alabama Pike Troy Arkansas Pike Delight Florida Bay Springfield Maine Penobscot Springfield
这里只有一个(微不足道的)函数依赖而且只有一个 候选键。唯一的 FD 是 State, County, City -> State, County, 城市。唯一的候选键是 {State, County, City}。这种关系 至少为 5NF。
你不能改善这种关系,但你可以改善 数据库。数据库不知道没有名为“Los”的县 Angeles”在阿拉巴马州。所以它会让你插入这个无效的行。
Cities State County City -- Alabama Los Angeles Troy
要修复 那个 问题,请添加一个包含所有有效 县,并设置外键引用。
Counties State -- Alabama Autauga Alabama Baldwin ... Alabama Pike ... California Los Angeles ...
关系"Counties"都是键,没有非素数 属性。 "Counties" 也至少在 5NF。
数据库仍然不知道它不应该允许这样的行。
Cities State County City -- Wales Pike Troy
美国没有名为 威尔士 的州。同样解决这个问题 方法作为最后一个问题。
States -- Alabama Arkansas ... California ...
并设置从县到州的外键引用。
这是标准 SQL 中的样子,只是我没有 供应所有 50 个州或所有 3000 多个县。
create table states (
state varchar(100) primary key
);
insert into states values
('Alabama'), ('Arkansas'), ('California'), ('Florida'),
('Maine'); -- and more . . .
create table counties (
county varchar(100) not null,
state varchar(100) not null,
primary key (county, state),
foreign key (state) references states (state)
on update restrict on delete restrict
);
insert into counties values
('Autauga', 'Alabama'), ('Baldwin', 'Alabama'), ('Pike', 'Alabama'),
('Pike', 'Arkansas'),
('Los Angeles', 'California'),
('Bay', 'Florida'),
('Penobscot', 'Maine'); -- and more . . .
create table cities (
city varchar(100) not null,
county varchar(100) not null,
state varchar(100) not null,
primary key (city, county, state),
foreign key (county, state) references counties (county, state)
on update restrict on delete restrict
);
insert into cities values
('Troy', 'Pike', 'Alabama'),
('Delight', 'Pike', 'Arkansas'),
('Springfield', 'Penobscot', 'Maine'),
('Springfield', 'Bay', 'Florida'); -- and more . . .
现在你会发现无法插入无效的元组 {特洛伊,洛杉矶,阿拉巴马}和{特洛伊,派克,威尔士}。
使用代理 ID 号代替自然键不会改变 正常形式。但它确实 改变了数据库的工作方式。并不是 一定是好的。
使用上面的 SQL 表,此更新将失败。
update states
set state = 'Wibble'
where state = 'Alabama';
这是一件好事。
让我们用代理 ID 号来构建这些表。
create table states (
state_id integer primary key,
state varchar(100) not null unique
);
insert into states values
(1, 'Alabama'), (2, 'Arkansas'), (3, 'California'), (4, 'Florida'),
(5, 'Maine'); -- and more . . .
create table counties (
county_id integer not null,
county varchar(100) not null,
state_id integer not null,
foreign key (state_id) references states (state_id)
on update restrict on delete restrict,
primary key (county_id, state_id),
unique (county, state_id)
);
insert into counties values
(1, 'Autauga', 1), (2, 'Baldwin', 1), (3, 'Pike', 1),
(4, 'Pike', 2),
(5, 'Los Angeles', 3),
(6, 'Bay', 4),
(7, 'Penobscot', 5); -- and more . . .
create table cities (
city_id integer not null,
city varchar(100) not null,
county_id integer not null,
state_id integer not null,
foreign key (county_id, state_id) references counties (county_id, state_id)
on update restrict on delete restrict,
primary key (city_id, county_id, state_id),
unique (city, county_id, state_id)
);
insert into cities values
(1, 'Troy', 3, 1),
(2, 'Delight', 4, 2),
(3, 'Springfield', 7, 5),
(4, 'Springfield', 6, 4); -- and more . . .
所有这三个表至少仍处于 5NF 状态。但是这个 (无效)更新现在将成功。
update states
set state = 'Wibble'
where state = 'Alabama';
这是一件坏事。
使用代理 ID 号使每个外键引用
具有与声明它们相同的行为 on update cascade
。恢复
on update restrict
的部分语义,你必须取
撤销更新权限的额外的、不直观的步骤
参考表。
几乎没有人能正确理解这一部分。
没有实际原则可以证明拆分主键是合理的 为了有一条你可以遵循的路径来恢复原来的路径 关系。换句话说,没有 relational 原则 证明改变这个...
Cities city_id city county_id state_id -- 1 Troy 3 2
...至此。
Cities city_id city county_id -- 1 Troy 3
Counties county_id county state_id -- 3 Pike 1
不仅没有关系原则可以证明分裂 主键,它 创建 关系模型的问题之一 旨在解决的数据。查找"IMS",一个分层数据库 管理系统,要求用户遵循路径 数据文件。