在单个表上使用多个唯一约束是否被认为是不良设计?


8

我查看了PostgreSQL的INSERT INTO .. ON CONFLICT (..) DO UPDATE ..语法并意识到,您不能使用它进行多个唯一的约束检查。我的意思是,您可以通过列名引用复合唯一索引ON CONFLICT (Name, Symbol)(如果为这两列定义了唯一索引),或者您可以使用主键。如果为列定义两个单独的唯一索引,则只能检查一个。

CREATE TABLE student
    (Id int primary key, Name varchar(50), Symbol varchar(50),
      CONSTRAINT col1_unique UNIQUE (Name),
      CONSTRAINT col2_unique UNIQUE (Symbol)
    ); 

INSERT INTO student
    (Id, Name, Symbol)
VALUES
    (1, 'John', 'J'),
    (2, 'David', 'D'),
    (3, 'Will', 'W');

INSERT INTO student
    (Id, Name, Symbol)
VALUES
    (4, 'Jeremy', 'J')
   on conflict(Name) DO UPDATE
   set Name = 'Jeremy';

可能抛出错误,说J是重复的。但是,此示例的设计很糟糕,因为Symbol应该位于另一个表中,并通过一对多关系连接到Student表。这就是为什么我想知道,也许PostgreSQL on conflict是按这种方式设计的,因为您总是可以以只有一个唯一索引的方式来重组表。是真的还是另一个原因?

小提琴示例:http ://www.sqlfiddle.com/#!17/ 9c0ce


您可以总是以一种唯一的唯一索引的方式重组表,其中有 EntityA和EntityB。每个实例有2个实例。任何EntityA实例都可以与任何EntityB实例结合,因此有2种可能的组合使用所有实例。实现了这些组合之一,您必须将其存储。现在尝试制定一个方案,其中不存在具有2个唯一性的表,并且具有所有约束来防止非法数据。
Akina

@Akina我想念你的意思。如果两个实体通过多对多关系连接,则将创建一个链接表,并存储它们的外键,因此不存在带有2个唯一索引的表。
appl3r

一个实例只能使用一次,因此在链接表中必须有2个uniqie索引(每个实体分别),以防止使用已经使用的实例。
Akina

虽然这是事实,但是这很麻烦:请参阅Michael Green答案中的示例。将这样一个简单的表分成4个表绝对是一件令人头疼的事,因为这是一个简单的字典,所以并不是您需要“ ON CONFLICT”选项。
Walfrat

Answers:


8

总是有第六个或域密钥普通形式。在这里,每个非关键列都成为它自己的表。因此3NF表T(Key,Col1,Col2,..)变为T1(Key,Col1),T2(Key,Col2)等。那些需要唯一性的新表可以声明它。

我认为在一个表上有多个唯一约束完全可以。以国家表为例。例如,这将具有ID,名称,ISO代码,首都和其他一些名称。前四个中的每个都将是唯一的。而且,如果我们希望我们的系统依赖于每个唯一性,我相信我们应该在每个上定义唯一性约束。这使所有消费者都可以依赖的数据成为事实。


您认为postgresql设计只是近视的结果吗?Oracle,SQL Server,DB2和其他所有提供了一种在这种情况下(使用MERGE语句)考虑所有唯一键的方法。pg ON CONFLICT DO UPDATE 仅在9.5中添加,并且限制更大。
appl3r

1
@ appl3r只是实现细节。您可以ON CONFLICT DO NOTHING不提及唯一约束,而它将考虑所有约束(不执行任何操作)。当您想做时ON CONFLICT DO UPDATE,您必须声明一列或一个约束,并且只声明一个。在将来的版本中可能会取消该限制。
ypercubeᵀᴹ

您的第一段让我有些困惑。假设我们将OP的Student(Id,Name,Symbol)表拆分为S1(Id,Name)和S2(Id,Symbol),以尝试将其制作为DK / NF。S2的(域和)关键约束是什么?它们如何确保每个学生都具有一个唯一的ID和一个唯一的符号?
Ilmari Karonen

1
问题是(样)“如果多个唯一指标都很好,为什么PostgreSQL需要,一个仲裁者索引指定ON CONFLICT ... DO UPDATE不幸的是这个答案并没有解决这一点。
AndreKR

@AndreKR解决了该问题(强制性):“(此Postgres功能)是通过这种方式设计的,因为您可以始终以只有一个唯一索引的方式来重组表吗?” 你当然可以添加其他的答案,解决你提到的点
ypercubeᵀᴹ
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.