def check_key(self, attribute, temp_keys): is_super_key = False for key in temp_keys: if set(set(key.Attributes)).issubset(attribute): is_super_key = True break if not is_super_key: if set(self.compute_attribute_closure(self.FDs, attribute)) == set(self.Attributes): key = Key() key.Attributes = attribute[:] temp_keys.append(key)
def compute_candidate_keys(self): temp_keys = [] left = [] # contains attributes appear 'only' on the left hand sides of FDs # 'left' attributes must be part of every key middle = [] # contains attributes appear on both left and right hand sides of FDs # 'middle' attributes may or may not part of a key right = [] # contains attributes appear 'only' on the right hand sides of FDs # 'right' attributes are not part of any key for fd in self.FDs: left += fd.leftHandSide right += fd.rightHandSide middle = list(set(left).intersection(set(right))) left = list(set(left)-set(middle)) right = list(set(right)-set(middle)) if len(left) > 0: # check keys in left list self.check_attribute_list(left, temp_keys) # if keys still not found, check keys in left list with middle list combinations if len(temp_keys) == 0: r1 = 1 while r1 != (len(left)+1): for left_combination in itertools.combinations(left, r1): r2 = 1 while r2 != (len(middle)+1): for middle_combination in itertools.combinations(middle, r2): self.check_key(list(left_combination) + list(middle_combination), temp_keys) #if len(temp_keys) > 0: # break r2 += 1 #if len(temp_keys) > 0: # break r1 += 1 else: # check keys in middle list self.check_attribute_list(middle, temp_keys) if len(temp_keys) == 0: key = Key() # Basic Key U->U: key.Attributes = self.Attributes temp_keys.append(key) self.Keys = temp_keys[:]
def decompose(self): if len(self.FdsViolateNF) > 0: nasty_fd = self.FdsViolateNF[0] lhs_closure = self.compute_attribute_closure(self.FDs, nasty_fd.leftHandSide) r1 = Relation() r1.Name = self.Name + "1" r1.Attributes = lhs_closure r1.compute_fds_from_original(self.canonical_cover) key = Key() key.Attributes = nasty_fd.leftHandSide r1.Keys.append(key) #r1.compute_candidate_keys() r1.computeNormalForm() r1.inherit_parent_foreign_keys(self.foreign_keys) self.decomposed_relations.append(r1) #if not (r1.NormalForm == '3NF' or r1.NormalForm == 'BCNF'): if r1.NormalForm != 'BCNF': r1.decompose() r2 = Relation() r2.Name = self.Name + "2" r2.Attributes = list(set(self.Attributes).difference(set(lhs_closure).difference(set(nasty_fd.leftHandSide)))) r2.compute_fds_from_original(self.canonical_cover) r2.compute_candidate_keys() r2.computeNormalForm() r2.inherit_parent_foreign_keys(self.foreign_keys) r2.foreign_keys.append(ForeignKey(nasty_fd.leftHandSide, r1)) self.decomposed_relations.append(r2) if r2.NormalForm != 'BCNF': r2.decompose() # here: ZT relation to preserve Z −> T remaining_fds = list((set(self.canonical_cover)-set(r1.FDs))-set(r2.FDs)) if len(remaining_fds) > 0: index = 3 for fd in remaining_fds: if set(fd.leftHandSide + fd.rightHandSide) == set(self.Attributes): self.FdsToDrop.append(fd) else: r = Relation() r.Name = self.Name + str(index) r.Attributes = fd.leftHandSide + fd.rightHandSide r.FDs.append(fd) r.compute_candidate_keys() r.computeNormalForm() self.decomposed_relations.append(r) r.inherit_parent_foreign_keys(self.foreign_keys) # Foreign Key computation: for key in r1.Keys: if key.Attributes == r.Attributes: r.foreign_keys.append(ForeignKey(key.Attributes, r1)) for key in r2.Keys: if key.Attributes == r.Attributes: r.foreign_keys.append(ForeignKey(key.Attributes, r2)) if r.NormalForm != 'BCNF': r.decompose() index += 1