外键表中其他列的唯一性约束

时间:2018-06-26 13:08:27

标签: sql foreign-keys unique-constraint

我有一些事物,它们具有0- *个名称,且具有任意数量的语言

CREATE TABLE Things(
    thing_id INT PRIMARY_KEY,
    thing_proprty INT);

CREATE TABLE ThingNames(
    thing_name_id INT PRIMARY_KEY,
    thing_id INT,
    language CHAR[2],
    name VARCHAR[64] UNIQUE,
    FOREIGN KEY (thing_id) REFERENCES Things(thing_id));

事物与许多字段相关,在每个字段中每种语言都有0-1个 CanonicalName 。直接的方法是

CREATE TABLE Fields(
    field_id INT PRIMARY_KEY,
    name VARCHAR[64])

CREATE TABLE CanonicalNames(
    thing_id INT
    field_id INT
    canonical_name_id INT
    FOREIGN KEY (thing_id) REFERENCES Things(thing_id),
    FOREIGN KEY (field_id) REFERENCES Fields(field_id),
    FOREIGN KEY (canonical_name_id) REFERENCES ThingNames(thing_name_id));

但是这错过了0-1约束,这是对 field_id 的唯一性约束,以及ThingNames的 thing_id language 列由 canonical_name_id 引用。在CanonicalNames中包括所有列作为外键当然是多余的并且容易出错,因此是否有办法在表之间施加唯一性约束?还是这里有我没有看到的更好的解决方案?

1 个答案:

答案 0 :(得分:0)

我不确定您的设计中有几件事。将ThingNames.name声明为键意味着同一事物在两种不同的语言中不能具有相同的名称,但是这似乎可能在相关语言(例如挪威语和丹麦语)中发生,或者在未翻译技术术语时发生。

相关性的概念未在您的模式中明确表示。仅当事物具有至少一个规范名称(对于某种语言)时,该事物才与该域相关吗?

但是,基于一些假设,我建议使用此模型(基于Dataphor的伪代码,省略数据类型):

create table Thing {
  ThingId,
  ThingProperty,
  key { ThingID }
};

create table Field {
  FieldId,
  FieldName,
  key { FieldId },
  key { FieldName } // Assumption - or can several Fields have the same name?
};

create table Relevance { // Standard many-to-many association table
  ThingId,
  FieldId,
  key { ThingId, FieldId },
  reference Relevance_Thing { ThingId } references Thing { ThingId },
  reference Relevance_Field { FieldId } references Field { FieldId }
};

create table ThingName {
  ThingName,
  Language,
  ThingId,
  key { ThingName, Language }, // Assuming the same thing may have the same name in different languages
  reference ThingName_Thing { ThingId } references Thing { ThingId }
};

create table CanonicalName {
  ThingId,
  FieldId,
  Language,
  CanonicalName,
  key { ThingId, FieldId, Language },
  reference CanonicalName_Relevance { ThingId, FieldId } references Relevance { ThingId, FieldId },
  reference CanonicalName_ThingName { ThingId, Language, CanonicalName } references ThingName { ThingId, Language, ThingName }
};

由于FD { Canonicalname, Language } -> { ThingId },CanonicalName不在BCNF中,但是冗余由引用CanonicalName_ThingName控制。 (您可以将其称为外键,但实际上它是外键。)这不是bug,而是通过这种方式确保规范名称是事物名称之一。 (我假设这是一个规则。)在这种设计中,在CanonicalName中具有Language列不是多余的,它可以启用您缺少的0-1约束。

此设计允许多个事物在不同语言中具有相同的名称,但也允许不同事物在不同语言中具有相同的名称。例如,“ kjole”在挪威语和丹麦语中均表示“着装”,而在挪威语中的“着装”在英语中则表示“西服”。让我知道是否应禁止这样做,我将更新设计。

如果有规则说事物与某个领域相关,并且且仅当该事物具有该领域的至少一个规范名称时,相关表可以(或应该省略)。当然,CanonicalName必须引用Field而不是Relevance。