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

Sql 外键表中其他列的唯一性约束,sql,foreign-keys,unique-constraint,Sql,Foreign Keys,Unique Constraint,我有一些东西在任何语言中都有0-*个名称: 这些内容在许多字段中都是相关的,在每个字段中,每种语言都有0-1个规范名称。直截了当的方法是 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 (t

我有一些东西在任何语言中都有0-*个名称:

这些内容在许多字段中都是相关的,在每个字段中,每种语言都有0-1个规范名称。直截了当的方法是

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约束,这将是对字段_id以及由canonical _name _id引用的ThingNames的thing _id和language列的唯一性约束。将所有列作为外键包含在CanonicalNames中当然是多余的,而且容易出错,那么,有没有一种方法可以跨表施加唯一性约束呢?或者这里有更好的解决方案,我没有看到?

我不确定您的设计中有几点。将ThingNames.name声明为key意味着同一事物在两种不同的语言中不能有相同的名称,但在相关语言(如挪威语和丹麦语)中,或者在技术术语未翻译的情况下,可能会出现这种情况

关联性的概念并没有在你的模式中明确地表达出来。仅当某个字段至少有一个规范名称(对于某些语言)时,它才与该字段相关吗

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

CanonicalName不在BCNF中,因为FD
{CanonicalName,Language}->{ThingId}
,但冗余由引用CanonicalName\u ThingName控制。(你可以称它为外键,但它实际上是一个外键。)这不是一个bug,而是如何确保规范名称是名称之一。(我假设这是一条规则。)在这个设计中,CanonicalName中有一个语言列并不是多余的,它启用了您缺少的0-1约束

这种设计允许多个事物在不同的语言中具有相同的名称,但也允许不同的事物在不同的语言中具有相同的名称。例如,“kjole”在挪威语和丹麦语中都是“dress”的意思,但在挪威语中“dress”在英语中是“suit”的意思。让我知道这是否应该被禁止,我会更新设计


如果有一条规则规定某个事物与某个字段相关,并且仅当该字段至少有一个规范名称时,关联表可能(或者可能应该)被省略。当然,CanonicalName必须引用字段而不是相关性。

您是指ThingNames中的唯一(thing_id,name)吗?不完全是。因为一个东西可能每种语言有0-*个名称,但每种字段和语言只有0-1个规范名称,所以我不能在ThingNames中施加唯一性约束。示例数据确实有助于解释这些关系。数据库标记也很有用。相关性是以与此问题正交的另一种方式处理的,但您是对的,对事物名称的唯一性约束太严格了。除此之外,你的建议本质上是我的前提是错误的,受控冗余(我坚持认为它是冗余,因为它没有告诉我任何我从规范名称id中不知道的东西)是可以接受的,甚至可能是必要的。我准备接受这一点作为答案,但如果其他人有其他观点,我会洗耳恭听。是的,CanonicalName.ThingId是多余的,正如我(可能间接地)所说,但它是确保每个事物、字段和语言最多有一个规范名称的关键约束所必需的,以及确保规范名称是事物名称之一的外部超键。无冗余模式必须使用更复杂的约束来强制执行这些规则,而SQL DBMS通常不支持这些约束。这是一个折衷方案,但由外键控制的冗余通常是最实际的解决方案。
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));
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 }
};