如何在多列之间强制执行唯一约束?

时间:2016-06-18 19:14:25

标签: database postgresql

我目前遇到类似的问题。我正在尝试创建一个表来存储有关父亲的信息。

假设所有父亲都有两个儿子,所有父亲将永远有两个孩子,不多也不少。

Father_Table

father_id   |   son1_id    |    son2_id   |   father_text_info
--------------------------------------------------------------
    13      |      8       |      11      |    "some info..."


Son_Table

   son_id   |     name       
----------------------------
    8       |     Moris    

我没有简单地将Son_Table信息添加到Father_Table中,因为Son_Table还会与其他表进行交互。

我的问题是,我如何创建TABLE以确保如果在Father_Table上已经存在son1_id或son2_id,那么它就不能在Father_Table上输入?

我已经尝试了以下内容:

CREATE TABLE father_table (
  father_id serial PRIMARY KEY,
  son1_id integer NOT NULL,
  son2_id integer NOT NULL,
  FOREIGN KEY (son1_id) REFERENCES Son_Table (son_id),
  FOREIGN KEY (son2_id) REFERENCES Son_Table (son_id),
  UNIQUE (son1_id, son2_id),
  UNIQUE (son2_id, son1_id),
  UNIQUE (son1_id),
  UNIQUE (son2_id)
)

但是仍然允许以下带有重复Son_Table Id的输入:

father_id   |   son1_id    |    son2_id   |   father_text_info
--------------------------------------------------------------
    13      |      8       |      11      |    "some info..."
--------------------------------------------------------------
    14      |      11      |       8      |    "other info..."

2 个答案:

答案 0 :(得分:0)

评论是对的。正常就是答案。即使使用PostgreSQL的高级功能,如果不对表进行规范化(或使用触发器创建标准化跟踪),我也无法找到使这种方法变得简单的方法。

问题是你可以轻松挑出最小和最大儿子ID。但是,如果没有非常可怕的性能问题,您无法覆盖设置操作中的所有情况。

将father_to_son_id分解为单独的表,或者使用触发器维护这样的表。然后一个简单的独特索引就可以了。

答案 1 :(得分:0)

尽管我同意其他人son1_idson2_id是糟糕的设计,但这是一个禁止重复的索引:

create extension intarray;
create unique index idx_two_sons on father_table (sort(ARRAY[son1_id, son2_id]));

如果将其与仅UNIQUE上的son1_id约束和son2_id上的{{1}}约束相结合,它应该可以执行您想要的操作。