我已经读过这句话: 数据取决于键[1NF],整个键[2NF],而仅取决于键[3NF]。
但是,我很难理解所谓的3.5NF或BCNF。这是我的理解:
- BCNF比3NF严格
- 表格中任何FD的左侧必须是超级键(或至少是候选键)
那么,为什么有些3NF表不在BCNF中?我的意思是,3NF引号明确表示“除了密钥”,这意味着所有属性仅取决于主键。毕竟,主键是候选键,直到被选为我们的主键为止。
到目前为止,如果对我的理解有任何不妥之处,请纠正我,并感谢您能提供的任何帮助。
我已经读过这句话: 数据取决于键[1NF],整个键[2NF],而仅取决于键[3NF]。
但是,我很难理解所谓的3.5NF或BCNF。这是我的理解:
那么,为什么有些3NF表不在BCNF中?我的意思是,3NF引号明确表示“除了密钥”,这意味着所有属性仅取决于主键。毕竟,主键是候选键,直到被选为我们的主键为止。
到目前为止,如果对我的理解有任何不妥之处,请纠正我,并感谢您能提供的任何帮助。
Answers:
您的披萨可以完全具有三种浇头类型:
因此,我们订购了两个比萨饼,然后选择以下浇头:
Pizza Topping Topping Type
-------- ---------- -------------
1 mozzarella cheese
1 pepperoni meat
1 olives vegetable
2 mozzarella meat
2 sausage cheese
2 peppers vegetable
等一下,马苏里拉奶酪既不能兼具奶酪又可以兼得肉!香肠不是奶酪!
我们需要防止此类错误,以使马苏里拉奶酪永远成为奶酪。为此,我们应该使用一个单独的表,因此我们只在一个地方写下该事实。
Pizza Topping
-------- ----------
1 mozzarella
1 pepperoni
1 olives
2 mozzarella
2 sausage
2 peppers
Topping Topping Type
---------- -------------
mozzarella cheese
pepperoni meat
olives vegetable
sausage meat
peppers vegetable
那是一个八岁的孩子可能理解的解释。这是更多技术版本。
仅当存在多个重叠的候选键时,BCNF与3NF的行为不同。
原因是X -> Y
如果Y
是的子集,则功能依赖项当然是正确的X
。因此,在只有一个候选键并且在3NF中的任何表中,它已经在BCNF中,因为除了该键之外,没有任何列在功能上依赖于任何内容的列(键或非键)。
因为每个披萨必须完全具有每种浇头类型之一,所以我们知道(Pizza,浇头类型)是候选键。我们还凭直觉知道给定的浇头不能同时属于不同的类型。因此(Pizza,Topping)必须是唯一的,因此也是候选关键字。因此,我们有两个重叠的候选键。
我显示了一个异常,我们将mozarella标记为错误的浇头类型。我们知道这是错误的,但是使它出错的规则是依赖性Topping -> Topping Type
,该依赖性对于此表的BCNF无效。除了整个候选键之外,它还依赖于其他东西。
因此,要解决此问题,我们从“披萨”表中删除“浇头类型”,并使其成为“浇头”表中的非关键属性。
微妙的区别是3NF区分了关键属性和非关键属性(也称为非主要属性),而BCNF则没有。
最好使用Zaniolo对3NF 的定义来解释,该定义等同于Codd的定义:
对于每个至少满足以下条件之一的非平凡FD(X-> A),关系R在3NF iff中:
(a)X是R的超键,或
(b)A是R的关键属性
BCNF要求(a),但不将(b)视为自己的特殊情况。换句话说,BCNF要求每个非平凡的行列式都是一个超键,即使其相关属性恰好是键的一部分。
对于满足R的每个非平凡FD(X-> A),BCNF中的关系R为满足以下条件:
(a)X是R的超键
因此,BCNF更加严格。
这种差异是如此微妙,以至于许多人非正式地将3NF称为BCNF。例如,您在此处说过3NF的意思是“数据取决于密钥……而仅取决于密钥”,但这实际上是对BCNF的非正式描述,而不是3NF。3NF可以更准确地描述为“ 非密钥数据取决于密钥……而仅取决于密钥”。
您还说过:
3NF引号明确表示“仅键”,意思是所有属性仅取决于主键。
这太简单了。3NF和BCNF以及所有范式都与所有候选键和/或超键有关,而不仅仅是一个“主”键。
使用BCNF定义
当且仅当对于它的每个依赖项X→Y,至少满足以下条件之一:
和3NF定义
对于且仅当针对其每个功能依赖项X→A时,至少满足以下条件之一:
而
哪里
也就是说,候选键的部分子集(除完整集外的任何非平凡子集)在功能上都不能依赖于超级键以外的任何东西。
不在BCNF中的表/关系会受到异常的影响,例如另一个用户在披萨示例中提到的更新异常。不幸,
当前可以在Wikipedia 上的“ 3NF表不满足BCNF(Boyce–Codd正常形式) ”中找到差异的示例,该表满足3NF但不满足BCNF,因为“网球场”(部分键/素数属性)取决于在“费率类型”(不是超级键的部分键/素数属性)上,这是一种依赖关系,我们可以通过询问数据库的客户网球俱乐部来确定:
今日的网球场预订(3NF,不是 BCNF)
Court Start Time End Time Rate Type
------- ---------- -------- ---------
1 09:30 10:30 SAVER
1 11:00 12:00 SAVER
1 14:00 15:30 STANDARD
2 10:00 11:30 PREMIUM-B
2 11:30 13:30 PREMIUM-B
2 15:00 16:30 PREMIUM-A
该表的超键是:
S1 = {Court, Start Time}
S2 = {Court, End Time}
S3 = {Rate Type, Start Time}
S4 = {Rate Type, End Time}
S5 = {Court, Start Time, End Time}
S6 = {Rate Type, Start Time, End Time}
S7 = {Court, Rate Type, Start Time}
S8 = {Court, Rate Type, End Time}
ST = {Court, Rate Type, Start Time, End Time}, the trivial superkey
3NF问题:部分键/主键属性“ Court”依赖于除超级键以外的其他东西。相反,它取决于部分键/主键属性“费率类型”。这意味着,如果我们升级法院,则用户必须手动更改费率类型,如果要应用费率更改,则必须手动更改法院。
(用技术术语来说,我们不能保证不会违反“费率类型”->“法院”功能的依赖。)
BCNF解决方案:如果要将上表放在BCNF中,我们可以将给定的关系/表分解为以下两个关系/表(假设我们知道费率类型仅取决于法院和会员资格,我们可以通过查询我们数据库的客户(网球俱乐部的所有者)发现:
费率类型(BCNF和较弱的3NF,这是BCNF隐含的)
Rate Type Court Member Flag
--------- ----- -----------
SAVER 1 Yes
STANDARD 1 No
PREMIUM-A 2 Yes
PREMIUM-B 2 No
当今的网球场预订量(BCNF和较弱的3NF,这是BCNF暗示的)
Member Flag Court Start Time End Time
----------- ----- ---------- --------
Yes 1 09:30 10:30
Yes 1 11:00 12:00
No 1 14:00 15:30
No 2 10:00 11:30
No 2 11:30 13:30
Yes 2 15:00 16:30
解决的问题:现在,如果我们升级法院,我们可以保证费率类型将反映这种变化,并且我们不会为法院收取错误的价格。
(从技术上讲,我们可以保证不会违反功能依赖性“费率类型”->“法院”。)
所有好的答案。用简单语言[BCNF]来表示,部分键不能依赖于键。
即,候选键的部分子集(即除完整集外的任何非平凡子集)在功能上都不能依赖于某个候选键。
“ smartnut007 ”,“ Bill Karwin ”和“ sqlvogel ” 的回答非常好。但是,让我提出一个有趣的观点。
好吧,我们有主键和非主键。
当我们关注非素数如何依赖素数时,我们看到两种情况:
非素数可以是依赖项,也可以不是。
不依赖时:可以没有依赖或传递依赖
素数之间的依赖性如何?
现在您知道,我们没有解决第二或第三NF 素数之间的依赖关系。此外,这种依赖性(如果有的话)是不希望的,因此我们有一条规则可以解决这个问题。这是BCNF。
参照Bill Karwin在此处发布的示例,您会注意到' Topping '和' Topping Type '都是主键并具有依赖性。如果它们不是具有依赖性的素数,那么3NF就可以加入。
注意:
BCNF的定义非常通用,并且没有区分素数和非素数的属性。然而,上述思维方式有助于理解即使在第二和第三次NF之后仍会渗入一些异常。
高级主题:将通用BCNF映射到2NF和3NF
既然我们知道BCNF提供了一个通用定义,而没有引用任何素数/非素数属性,那么让我们看看BCNF和2/3 NF是如何关联的。
首先,BCNF要求(除一般情况外)对于每个功能依赖项X -> Y
(FD),X应该是超键。如果仅考虑任何FD,那么我们有三种情况-(1)X和Y均为非素数,(2)素数和(3)X素数和Y非素数,丢弃(无意义的)情况X非-素数和Y素数。
对于情况(1),由3NF负责。
对于情况(3),由2NF负责。
对于情况(2),我们发现使用BCNF
这是一个古老的问题,提供了有价值的答案,但直到发现一个真实的例子来说明3NF的问题,我还是有些困惑。也许不适合8岁的孩子,但希望对您有所帮助。
明天我将在每个季度的家长/老师会议中与长女的老师见面。这是我的日记的样子(名称和房间已更改):
Teacher | Date | Room
----------|------------------|-----
Mr Smith | 2018-12-18 18:15 | A12
Mr Jones | 2018-12-18 18:30 | B10
Ms Doe | 2018-12-18 18:45 | C21
Ms Rogers | 2018-12-18 19:00 | A08
每个房间只有一位老师,他们永远都不会动。如果你看看,你会发现:(1)每个属性Teacher
,Date
,Room
,我们有每行只有一个值。(2)超键是:(Teacher, Date, Room)
,(Teacher, Date)
并且(Date, Room)
和候选键显然(Teacher, Date)
和(Date, Room)
。
(Teacher, Room)
不是超级键,因为我将在下个季度完成表格,并且我可能会有这样的一行(史密斯先生没有动!):
Teacher | Date | Room
---------|------------------| ----
Mr Smith | 2019-03-19 18:15 | A12
我们可以得出什么结论?(1)是非正式但正确的1NF公式。从(2)中我们看到没有“非主要属性”:免费提供2NF和3NF。
我的日记是3NF。好!不。不是真的,因为没有数据建模者会在数据库模式中接受此设置。该Room
属性取决于该Teacher
属性(再次:教师不要移动!),但是架构不能反映这一事实。一个理智的数据建模者会做什么?将表一分为二:
Teacher | Date
----------|-----------------
Mr Smith | 2018-12-18 18:15
Mr Jones | 2018-12-18 18:30
Ms Doe | 2018-12-18 18:45
Ms Rogers | 2018-12-18 19:00
和
Teacher | Room
----------|-----
Mr Smith | A12
Mr Jones | B10
Ms Doe | C21
Ms Rogers | A08
但是3NF不能处理主要属性依赖性。问题是:在某些情况下,符合3NF标准不足以确保合理的表架构设计。
使用BCNF,您无需担心2NF和3NF规则中的属性是否是质数属性。对于每个非平凡的依赖关系(子集显然由其超集确定),行列式是一个完整的超键。换句话说,除了一个完整的超级键(不包括琐碎的FD)之外,没有什么决定。(有关正式定义,请参见其他答案)。
一旦Room
依靠Teacher
,Room
必须是Teacher
(不是这种情况的)子集,或者Teacher
必须是一个超级键(我的日记中不是这种情况,但是拆分表时就是这种情况)。
总结:BNCF比3NF更严格,但我认为更容易掌握: