验证非键列依赖和传递依赖
Verifying non-key column dependencies and transitive dependencies
我正在设计我的第一个数据库,我正在尝试遵循高达 3NF 的规范化规则。我使用以下定义进行规范化:
- 1NF: 没有重复组并且识别出主键。
- 2NF:删除了部分密钥依赖项。所有非键列都完全依赖于主键。
- 3NF:移除了传递依赖和非键依赖。
table用于存储宠物食品的信息。这是任何规范化之前 table 的基本示例:
╔════════════╦═════════╦═════════════╦════════════╦═══════════╦═══════════════╦═══════╗
║ Brand ║ Flavor ║ Animal Type ║ Breed Size ║ Age Group ║ Ingredients ║ Price ║
╠════════════╬═════════╬═════════════╬════════════╬═══════════╬═══════════════╬═══════╣
║ Purina ║ Chicken ║ Dog ║ Small ║ Adult ║ Chicken, Salt ║ 18.99 ║
╠════════════╬═════════╬═════════════╬════════════╬═══════════╬═══════════════╬═══════╣
║ BlueWilder ║ Chicken ║ Dog ║ Small ║ Adult ║ Chicken, Salt ║ 18.99 ║
╚════════════╩═════════╩═════════════╩════════════╩═══════════╩═══════════════╩═══════╝
按照上面的1NF定义,我添加了一个主键列。在这种情况下,唯一的问题是每条记录包含多个条目的成分列:
╔═════════╦════════════╦═════════╦═════════════╦════════════╦═══════════╦═════════════╦═══════╗
║ Food ID ║ Brand ║ Flavor ║ Animal Type ║ Breed Size ║ Age Group ║ Ingredients ║ Price ║
╠═════════╬════════════╬═════════╬═════════════╬════════════╬═══════════╬═════════════╬═══════╣
║ 1 ║ Purina ║ Chicken ║ Dog ║ Small ║ Adult ║ Chicken ║ 18.99 ║
╠═════════╬════════════╬═════════╬═════════════╬════════════╬═══════════╬═════════════╬═══════╣
║ 1 ║ Purina ║ Chicken ║ Dog ║ Small ║ Adult ║ Salt ║ 18.99 ║
╠═════════╬════════════╬═════════╬═════════════╬════════════╬═══════════╬═════════════╬═══════╣
║ 2 ║ BlueWilder ║ Chicken ║ Dog ║ Small ║ Adult ║ Chicken ║ 18.99 ║
╠═════════╬════════════╬═════════╬═════════════╬════════════╬═══════════╬═════════════╬═══════╣
║ 2 ║ BlueWilder ║ Chicken ║ Dog ║ Small ║ Adult ║ Salt ║ 18.99 ║
╚═════════╩════════════╩═════════╩═════════════╩════════════╩═══════════╩═════════════╩═══════╝
由于成分列,现在有一个重复组。为了解决这个问题,我创建了两个单独的 table;成分 table,以及将成分 table 和食物 table 连接在一起的关联词 table:
╔═══════════════╦════════════╗
║ Ingredient ID ║ Ingredient ║
╠═══════════════╬════════════╣
║ 1 ║ Chicken ║
╠═══════════════╬════════════╣
║ 2 ║ Salt ║
╚═══════════════╩════════════╝
╔═════════╦═══════════════╗
║ Food ID ║ Ingredient ID ║
╠═════════╬═══════════════╣
║ 1 ║ 1 ║
╠═════════╬═══════════════╣
║ 1 ║ 2 ║
╠═════════╬═══════════════╣
║ 2 ║ 1 ║
╠═════════╬═══════════════╣
║ 2 ║ 2 ║
╚═════════╩═══════════════╝
现在,我可以从食物中删除成分列 table:
╔═════════╦════════════╦═════════╦═════════════╦════════════╦═══════════╦═══════╗
║ Food ID ║ Brand ║ Flavor ║ Animal Type ║ Breed Size ║ Age Group ║ Price ║
╠═════════╬════════════╬═════════╬═════════════╬════════════╬═══════════╬═══════╣
║ 1 ║ Purina ║ Chicken ║ Dog ║ Small ║ Adult ║ 18.99 ║
╠═════════╬════════════╬═════════╬═════════════╬════════════╬═══════════╬═══════╣
║ 2 ║ BlueWilder ║ Chicken ║ Dog ║ Small ║ Adult ║ 18.99 ║
╚═════════╩════════════╩═════════╩═════════════╩════════════╩═══════════╩═══════╝
此时,我不确定如何进行。
我的思路是这样的:如果任何非主键列的值发生变化,那么Food ID一定是不同的。例如,品牌、风味、品种大小、年龄段、成分和价格都可以相同。但是如果动物类型是狗,然后变成猫,那肯定是不同的记录。这适用于所有非主键列。按照这种思路,所有非主键列都完全依赖于主键,不存在传递依赖。
我的思路对吗?根据我上面列出的定义,2NF 和 3NF 是否已经满足?
要在屏幕上保存 space 我将重命名属性:
- 品牌:
BRD
- 风味:
FLA
- 动物:
ANM
- 品种规格:
SIZ
- 年龄段:
AGP
- 成分:
ING
- 价格:
PRI
方法一
规范化,如教科书所述。
步骤 1.1
由于 ingredients 中的重复组,table 中的值不是关系,因此 table 不代表关系变量,因此在 1NF 中它是 not。解决方案是确保 ingredient 列 (ING
) 每行 exactly one 成分——正如您所做的那样。但是,没有添加新属性(没有新 ID)。现在我们有(在 1NF 中):
R {BRD, FLA, ANM, SIZ, AGP, ING, PRI}
整个标题是关键。
步骤 1.2
来自 FDs
:
{BRD, FLA} -> {ANM}
{BRD, FLA} -> {SIZ}
{BRD, FLA} -> {AGP}
{BRD, FLA} -> {PRI}
通过对 FD 和 Heath 定理应用并集规则:
R1 {BRD, FLA, ANM, SIZ, AGP, PRI}
KEY {BRD, FLA}
R2 {BRD, FLA, ING}
KEY {BRD, FLA, ING}
完成。就是这样,如果我得到 FDs
正确的话。
两者都在 BCNF 中,我有信心说 R1 在 5NF 中,R2 在 6NF 中。
方法二
Database design is predicate design.
不是大多数教科书中的正式归一化方法,而是设计方法导致tables处于高NF(5NF,6NF)。
第一步,使用简单谓词和相关约束来描述问题(业务领域)。然后可以使用逻辑自然语言推理问题。
一个简单的谓词不能在不丢失信息的情况下分解,它的匹配relvar在6NF.
在第二步中,可以将这些简单谓词(和匹配的关系变量)组合起来,确保不引入冗余和逻辑错误的可能性,即矛盾。完成后,relvars (tables) 预计将在 5NF 中。
步骤 2.1
使用简单谓词描述问题并匹配 6NF 关系变量。不表达约束(它得到 long-winded),只是陈述它们。
-- Brand BRD exists.
--
brand {BRD}
PK {BRD}
-- Flavor FLA exists.
--
flavor {FLA}
PK {FLA}
-- Animal type ANM exists.
--
animal {ANM}
PK {ANM}
-- Breed size SIZ exists.
--
bsize {SIZ}
PK {SIZ}
-- Age group AGP exists.
--
age {AGP}
PK {AGP}
-- Ingredient ING exists.
--
ingredient {ING}
PK {ING}
-- Pet food with flavor FLA made by brand BRD
-- is for animal type ANM.
--
food {BRD, FLA, ANM}
PK {BRD, FLA}
FK1 {BRD} REFERENCES brand {BRD}
FK2 {FLA} REFERENCES flavor {FLA}
FK3 {ANM} REFERENCES animal {ANM}
-- Pet food with flavor FLA made by brand BRD
-- is recommended for breed size SIZ.
--
food_bsize {BRD, FLA, SIZ}
PK {BRD, FLA}
FK1 {BRD, FLA} REFERENCES
food {BRD, FLA}
FK2 {SIZ} REFERENCES bsize {SIZ}
-- Pet food with flavor FLA made by brand BRD
-- is recommended for breed age group AGP.
--
food_age {BRD, FLA, AGP}
PK {BRD, FLA}
FK1 {BRD, FLA} REFERENCES
food {BRD, FLA}
FK2 {AGP} REFERENCES age {AGP}
-- Pet food with flavor FLA made by brand BRD
-- is priced at PRI Euros per unit.
--
price {BRD, FLA, PRI}
PK {BRD, FLA}
FK {BRD, FLA} REFERENCES
food {BRD, FLA}
-- Pet food with flavor FLA made by brand BRD
-- contains ingredient ING.
--
recipe {BRD, FLA, ING}
PK {BRD, FLA, ING}
FK1 {BRD, FLA} REFERENCES
food {BRD, FLA}
FK2 {ING} REFERENCES ingredient {ING}
步骤 2.2
只看键位,我们可以看到food, food_bsize, food_age和价格table可以合并
-- Pet food with flavor FLA made by brand BRD
-- is for animal type ANM, recommended for
-- breed size SIZ, breed age group AGP; priced
-- at PRI Euros per unit.
--
food_ {BRD, FLA, ANM, SIZ, AGP, PRI}
PK {BRD, FLA}
FK1 {BRD} REFERENCES brand {BRD}
FK2 {FLA} REFERENCES flavor {FLA}
FK3 {ANM} REFERENCES animal {ANM}
FK4 {SIZ} REFERENCES bsize {SIZ}
FK5 {AGP} REFERENCES age {AGP}
如果我们决定不保留前六个table定义域,那么最终结果与第一种方法一样:
food_ {BRD, FLA, ANM, SIZ, AGP, PRI}
PK {BRD, FLA}
recipe {BRD, FLA, ING}
PK {BRD, FLA, ING}
FK {BRD, FLA} REFERENCES food_
{BRD, FLA}
但是,在 real-world 项目中,您可能需要 brand、flavor、animal 、bsize 和 age tables 来约束域。规范化中没有规定你应该拥有它们。
此外,并非所有属性都同时已知,因此您不太可能将所有 food、food_bsize、food_age 和 价格 tables 到 food_。这将取决于业务流程和属性的可选性。
添加 ID
添加代理键 (ID) 与规范化无关。您可能出于其他原因需要添加它们,请查看 this example.
注:
All attributes (columns) NOT NULL
KEY = PK or AK
PK = Primary Key
AK = Alternate Key (Unique)
SK = Proper Superkey (Unique)
FK = Foreign Key
我一直用第二种方法来设计。从未见过第一个在某种正式的数据库课程之外使用的;以及寻求有关 SO 帮助的人。
出于某种原因,超出我的理解,方法 1 在 方法 2 之前在主题为“数据库设计”的数据库课程中教授。大多数学校根本不教方法2。去图吧。
我正在设计我的第一个数据库,我正在尝试遵循高达 3NF 的规范化规则。我使用以下定义进行规范化:
- 1NF: 没有重复组并且识别出主键。
- 2NF:删除了部分密钥依赖项。所有非键列都完全依赖于主键。
- 3NF:移除了传递依赖和非键依赖。
table用于存储宠物食品的信息。这是任何规范化之前 table 的基本示例:
╔════════════╦═════════╦═════════════╦════════════╦═══════════╦═══════════════╦═══════╗
║ Brand ║ Flavor ║ Animal Type ║ Breed Size ║ Age Group ║ Ingredients ║ Price ║
╠════════════╬═════════╬═════════════╬════════════╬═══════════╬═══════════════╬═══════╣
║ Purina ║ Chicken ║ Dog ║ Small ║ Adult ║ Chicken, Salt ║ 18.99 ║
╠════════════╬═════════╬═════════════╬════════════╬═══════════╬═══════════════╬═══════╣
║ BlueWilder ║ Chicken ║ Dog ║ Small ║ Adult ║ Chicken, Salt ║ 18.99 ║
╚════════════╩═════════╩═════════════╩════════════╩═══════════╩═══════════════╩═══════╝
按照上面的1NF定义,我添加了一个主键列。在这种情况下,唯一的问题是每条记录包含多个条目的成分列:
╔═════════╦════════════╦═════════╦═════════════╦════════════╦═══════════╦═════════════╦═══════╗
║ Food ID ║ Brand ║ Flavor ║ Animal Type ║ Breed Size ║ Age Group ║ Ingredients ║ Price ║
╠═════════╬════════════╬═════════╬═════════════╬════════════╬═══════════╬═════════════╬═══════╣
║ 1 ║ Purina ║ Chicken ║ Dog ║ Small ║ Adult ║ Chicken ║ 18.99 ║
╠═════════╬════════════╬═════════╬═════════════╬════════════╬═══════════╬═════════════╬═══════╣
║ 1 ║ Purina ║ Chicken ║ Dog ║ Small ║ Adult ║ Salt ║ 18.99 ║
╠═════════╬════════════╬═════════╬═════════════╬════════════╬═══════════╬═════════════╬═══════╣
║ 2 ║ BlueWilder ║ Chicken ║ Dog ║ Small ║ Adult ║ Chicken ║ 18.99 ║
╠═════════╬════════════╬═════════╬═════════════╬════════════╬═══════════╬═════════════╬═══════╣
║ 2 ║ BlueWilder ║ Chicken ║ Dog ║ Small ║ Adult ║ Salt ║ 18.99 ║
╚═════════╩════════════╩═════════╩═════════════╩════════════╩═══════════╩═════════════╩═══════╝
由于成分列,现在有一个重复组。为了解决这个问题,我创建了两个单独的 table;成分 table,以及将成分 table 和食物 table 连接在一起的关联词 table:
╔═══════════════╦════════════╗
║ Ingredient ID ║ Ingredient ║
╠═══════════════╬════════════╣
║ 1 ║ Chicken ║
╠═══════════════╬════════════╣
║ 2 ║ Salt ║
╚═══════════════╩════════════╝
╔═════════╦═══════════════╗
║ Food ID ║ Ingredient ID ║
╠═════════╬═══════════════╣
║ 1 ║ 1 ║
╠═════════╬═══════════════╣
║ 1 ║ 2 ║
╠═════════╬═══════════════╣
║ 2 ║ 1 ║
╠═════════╬═══════════════╣
║ 2 ║ 2 ║
╚═════════╩═══════════════╝
现在,我可以从食物中删除成分列 table:
╔═════════╦════════════╦═════════╦═════════════╦════════════╦═══════════╦═══════╗
║ Food ID ║ Brand ║ Flavor ║ Animal Type ║ Breed Size ║ Age Group ║ Price ║
╠═════════╬════════════╬═════════╬═════════════╬════════════╬═══════════╬═══════╣
║ 1 ║ Purina ║ Chicken ║ Dog ║ Small ║ Adult ║ 18.99 ║
╠═════════╬════════════╬═════════╬═════════════╬════════════╬═══════════╬═══════╣
║ 2 ║ BlueWilder ║ Chicken ║ Dog ║ Small ║ Adult ║ 18.99 ║
╚═════════╩════════════╩═════════╩═════════════╩════════════╩═══════════╩═══════╝
此时,我不确定如何进行。
我的思路是这样的:如果任何非主键列的值发生变化,那么Food ID一定是不同的。例如,品牌、风味、品种大小、年龄段、成分和价格都可以相同。但是如果动物类型是狗,然后变成猫,那肯定是不同的记录。这适用于所有非主键列。按照这种思路,所有非主键列都完全依赖于主键,不存在传递依赖。
我的思路对吗?根据我上面列出的定义,2NF 和 3NF 是否已经满足?
要在屏幕上保存 space 我将重命名属性:
- 品牌:
BRD
- 风味:
FLA
- 动物:
ANM
- 品种规格:
SIZ
- 年龄段:
AGP
- 成分:
ING
- 价格:
PRI
方法一
规范化,如教科书所述。
步骤 1.1
由于 ingredients 中的重复组,table 中的值不是关系,因此 table 不代表关系变量,因此在 1NF 中它是 not。解决方案是确保 ingredient 列 (ING
) 每行 exactly one 成分——正如您所做的那样。但是,没有添加新属性(没有新 ID)。现在我们有(在 1NF 中):
R {BRD, FLA, ANM, SIZ, AGP, ING, PRI}
整个标题是关键。
步骤 1.2
来自 FDs
:
{BRD, FLA} -> {ANM}
{BRD, FLA} -> {SIZ}
{BRD, FLA} -> {AGP}
{BRD, FLA} -> {PRI}
通过对 FD 和 Heath 定理应用并集规则:
R1 {BRD, FLA, ANM, SIZ, AGP, PRI}
KEY {BRD, FLA}
R2 {BRD, FLA, ING}
KEY {BRD, FLA, ING}
完成。就是这样,如果我得到 FDs
正确的话。
两者都在 BCNF 中,我有信心说 R1 在 5NF 中,R2 在 6NF 中。
方法二
Database design is predicate design.
不是大多数教科书中的正式归一化方法,而是设计方法导致tables处于高NF(5NF,6NF)。
第一步,使用简单谓词和相关约束来描述问题(业务领域)。然后可以使用逻辑自然语言推理问题。
一个简单的谓词不能在不丢失信息的情况下分解,它的匹配relvar在6NF.
在第二步中,可以将这些简单谓词(和匹配的关系变量)组合起来,确保不引入冗余和逻辑错误的可能性,即矛盾。完成后,relvars (tables) 预计将在 5NF 中。
步骤 2.1
使用简单谓词描述问题并匹配 6NF 关系变量。不表达约束(它得到 long-winded),只是陈述它们。
-- Brand BRD exists.
--
brand {BRD}
PK {BRD}
-- Flavor FLA exists.
--
flavor {FLA}
PK {FLA}
-- Animal type ANM exists.
--
animal {ANM}
PK {ANM}
-- Breed size SIZ exists.
--
bsize {SIZ}
PK {SIZ}
-- Age group AGP exists.
--
age {AGP}
PK {AGP}
-- Ingredient ING exists.
--
ingredient {ING}
PK {ING}
-- Pet food with flavor FLA made by brand BRD
-- is for animal type ANM.
--
food {BRD, FLA, ANM}
PK {BRD, FLA}
FK1 {BRD} REFERENCES brand {BRD}
FK2 {FLA} REFERENCES flavor {FLA}
FK3 {ANM} REFERENCES animal {ANM}
-- Pet food with flavor FLA made by brand BRD
-- is recommended for breed size SIZ.
--
food_bsize {BRD, FLA, SIZ}
PK {BRD, FLA}
FK1 {BRD, FLA} REFERENCES
food {BRD, FLA}
FK2 {SIZ} REFERENCES bsize {SIZ}
-- Pet food with flavor FLA made by brand BRD
-- is recommended for breed age group AGP.
--
food_age {BRD, FLA, AGP}
PK {BRD, FLA}
FK1 {BRD, FLA} REFERENCES
food {BRD, FLA}
FK2 {AGP} REFERENCES age {AGP}
-- Pet food with flavor FLA made by brand BRD
-- is priced at PRI Euros per unit.
--
price {BRD, FLA, PRI}
PK {BRD, FLA}
FK {BRD, FLA} REFERENCES
food {BRD, FLA}
-- Pet food with flavor FLA made by brand BRD
-- contains ingredient ING.
--
recipe {BRD, FLA, ING}
PK {BRD, FLA, ING}
FK1 {BRD, FLA} REFERENCES
food {BRD, FLA}
FK2 {ING} REFERENCES ingredient {ING}
步骤 2.2
只看键位,我们可以看到food, food_bsize, food_age和价格table可以合并
-- Pet food with flavor FLA made by brand BRD
-- is for animal type ANM, recommended for
-- breed size SIZ, breed age group AGP; priced
-- at PRI Euros per unit.
--
food_ {BRD, FLA, ANM, SIZ, AGP, PRI}
PK {BRD, FLA}
FK1 {BRD} REFERENCES brand {BRD}
FK2 {FLA} REFERENCES flavor {FLA}
FK3 {ANM} REFERENCES animal {ANM}
FK4 {SIZ} REFERENCES bsize {SIZ}
FK5 {AGP} REFERENCES age {AGP}
如果我们决定不保留前六个table定义域,那么最终结果与第一种方法一样:
food_ {BRD, FLA, ANM, SIZ, AGP, PRI}
PK {BRD, FLA}
recipe {BRD, FLA, ING}
PK {BRD, FLA, ING}
FK {BRD, FLA} REFERENCES food_
{BRD, FLA}
但是,在 real-world 项目中,您可能需要 brand、flavor、animal 、bsize 和 age tables 来约束域。规范化中没有规定你应该拥有它们。
此外,并非所有属性都同时已知,因此您不太可能将所有 food、food_bsize、food_age 和 价格 tables 到 food_。这将取决于业务流程和属性的可选性。
添加 ID
添加代理键 (ID) 与规范化无关。您可能出于其他原因需要添加它们,请查看 this example.
注:
All attributes (columns) NOT NULL
KEY = PK or AK
PK = Primary Key
AK = Alternate Key (Unique)
SK = Proper Superkey (Unique)
FK = Foreign Key
我一直用第二种方法来设计。从未见过第一个在某种正式的数据库课程之外使用的;以及寻求有关 SO 帮助的人。 出于某种原因,超出我的理解,方法 1 在 方法 2 之前在主题为“数据库设计”的数据库课程中教授。大多数学校根本不教方法2。去图吧。