【问题标题】:Functional dependencies in database数据库中的功能依赖
【发布时间】:2017-03-30 16:35:52
【问题描述】:

我对关系有以下一组函数依赖 架构r(A, B, C, D, E, F )

A -> BCD
BC -> DE
B -> D
D -> A

谁能解释如何找到这个关系的候选键?

【问题讨论】:

  • 你自己付出了什么努力?
  • 据我所知,我有 (ABCDE) + = ABCDE,这意味着 ABCDE 的任何子集都不能形成候选键,还有 (BF ) + = (DF ) + = ABCDEF。因此,我认为候选键是AFBFDF。 AF 因为它是一个超级键。不确定是否正确。 @WillemVanOnsem
  • 请将您的评论编辑到您的问题中,它不属于评论。还请参考您正在遵循的流程/算法以及您所做的事情;否则我们不能就你所做的事情说你应该做什么或做错了什么。例如,您的“因此”是不合理的,但是您没有解释您所做的事情如何给出您的一组 CK 的(il)逻辑。您当前的问题“如何找到 CKs”太宽泛了——它要求教科书的一部分,根据您的示例量身定制。因此,请根据上述内容确定您的问题,以便针对非常具体的情况提出问题。
  • “我有以下一组 FD”不足以回答这个问题。你需要有一套你知道是封面的东西。所以找出那是什么。

标签: database database-normalization relational-algebra functional-dependencies


【解决方案1】:

简答:候选键为(A,F)(B,F)(D,F ).

像这样Wikipedia article 说:

可以计算所有候选键的集合,例如从一组 功能依赖。为此我们需要定义属性 属性集α的闭包α+。套装 α+ 包含功能上的所有属性 由α暗示。

找到一个候选键非常简单。我们从一个 设置 α 个属性并尝试依次删除每个 属性。如果在删除属性后属性闭包 保持不变,那么这个属性不是必需的,我们可以 永久删除。我们称结果为 minimize(α)。如果 α 是所有属性的集合,则 minimize(α) 是候选键。

所以现在我们只需要把它付诸实践。让我们从所有属性 α0=(A,B,C,D,E,F)开始。现在我们可以看看删除 A 是否会产生问题。 α'0=(B,C,D,E,F), α'0+ sup> 是 (B,C,D,E,F,A)(因为 D→ A 成立)。现在通过永久踢出 A 并尝试删除 B,我们将得到 a 候选键。

  1. α1=(B,C,D,E,F)。我们可以扔掉B吗?是的,因为 α'1=(C,D,E,F) 将导致 α'1+=(A,B,C,D,E,F)(因为 D→AA→BCD)。
  2. α2=(C,D,E,F)。我们可以扔掉 C 吗?是的,因为 α'2=(D,E,F) 将导致 α'2+=(A,B,C,D,E,F)(因为 D→AA→BCD)。
  3. α3=(D,E,F)。我们可以扔掉 D 吗?否,因为 α'3=(E,F) 将导致 α'3+= (E,F).
  4. α3=(D,E,F)。我们可以扔掉E吗?是的,因为 α'3=(D,F) 将导致 α'3+= (A,B,C,D,E,F)(从 D→AA→BCD;和 BC→DE em>)。
  5. α4=(D,F)。我们可以扔掉F吗?不,因为 α'4=(D) 将导致 α'4+=(A ,B,C,D,E)(自D→AA→BCD;和BC→DE)。

所以现在我们生成了 minimize(α0)=α4=(D,F)。我们可以使用 brute force 方法,在每次迭代中,我们遍历所有可以删除的可能键。但这将花费指数时间来生成。

Wikipedia 文章包含了一种生成所有候选键多项式键的数量和函数依赖关系的方法。算法定义为:

function find_candidate_keys(A, F)
/* A is the set of all attributes and F is the set of functional dependencies */
K[0] := minimize(A);
n := 1; /* Number of Keys known so far */
i := 0; /* Currently processed key */
while i < n do
  foreach α → β ∈ F do
    /* Build a new potential key from the previous known key and the current FD */
    S := α ∪ (K[i] − β);
    /* Search whether the new potential key is part of the already known keys */ 
    found := false;
    for j := 0 to n-1 do
      if K[j] ⊆ S then found := true;
    /* If not, add if 
    if not found then
      K[n] := minimize(S);
      n := n + 1;
  i := i + 1
return K

所以如果我们运行算法,我们首先必须计算 minimize(A),但好消息是:我们已经在上面做了。所以 K[0] = (D,F), n=1i=0

现在我们使用 while 循环并开始迭代所有函数依赖项。

  1. 对于A&rightarrow; BCD。所以现在我们构造一个键(A,F)。我们检查是否已经有一个子集定义为键(不是这种情况)。现在我们将其最小化,例如:(A,F)&rightarrow;(A,F)。所以我们添加了一个新的键(A,F)
  2. 对于BC&rightarrow;DE。所以现在我们构造一个键(B,C,F)。我们检查是否已经有一个子集定义为键(不是这种情况)。现在我们将其最小化,例如 (B,C,F)&rightarrow;(B,F)&rightarrow;(B,F)。所以我们添加 (B,F)
  3. B&rightarrow;D。所以现在我们构造一个键(B,F)。我们检查是否已经有一个子集定义为键(就是这种情况)。我们不添加这个。
  4. D&rightarrow;A。所以现在我们构造一个键(D,F)。我们检查是否已经有一个子集定义为键(就是这种情况)。我们不添加这个。

这是第一次迭代的结束。所以 K 现在是 K=[(D,F),(A,F),(B,F)]n=3 现在是 i=1。所以对于 K[i]=(A,F) 我们现在迭代:

  1. 对于A&rightarrow; BCD。所以现在我们构造一个键(A,F)。我们检查是否已经有一个子集定义为键(就是这种情况)。我们不添加这个。
  2. 对于BC&rightarrow;DE。所以现在我们构造一个键(B,C,F)。我们检查是否已经有一个子集定义为键(就是这种情况)。我们不添加这个。
  3. B&rightarrow;D。所以现在我们构造一个键(A,B,F)。我们检查是否已经有一个子集定义为键(就是这种情况)。我们不添加这个。
  4. D&rightarrow;A。所以现在我们构造一个键(D,F)。我们检查是否已经有一个子集定义为键(就是这种情况)。我们不添加这个。

这是第二次迭代的结束。所以 K 现在是 K=[(D,F),(A,F),(B,F)]n=3 和现在 i=2。所以对于 K[i]=(B,F) 我们现在迭代:

  1. 对于A&rightarrow; BCD。所以现在我们构造一个键(A,F)。我们检查是否已经有一个子集定义为键(就是这种情况)。我们不添加这个。
  2. 对于BC&rightarrow;DE。所以现在我们构造一个键(B,C,F)。我们检查是否已经有一个子集定义为键(就是这种情况)。我们不添加这个。
  3. B&rightarrow;D。所以现在我们构造一个键(B,F)。我们检查是否已经有一个子集定义为键(就是这种情况)。我们不添加这个。
  4. D&rightarrow;A。所以现在我们构造一个键(B,D,F)。我们检查是否已经有一个子集定义为键(就是这种情况)。我们不添加这个。

所以最后 K=[(D,F),(A,F),(B,F)]。这些都是候选键。

【讨论】:

  • @philipxy:但这计算了闭包:因为我们重复这样做。如果找到新的 CK,我们将通过再次对该密钥执行所有 FD 来处理它,因此最终我们搜索所有这些。关键是我们可以说是“即时”计算闭包。
  • 您的评论不清楚,但我看到该算法的论文发现 CKs 有一个封面。
猜你喜欢
  • 1970-01-01
  • 2016-03-26
  • 1970-01-01
  • 2015-06-28
  • 1970-01-01
  • 2014-05-09
  • 1970-01-01
  • 2013-01-09
  • 2010-12-18
相关资源
最近更新 更多