有条件地限制一个表字段不能被另一个表引用?

时间:2019-01-24 23:45:56

标签: sql postgresql constraints unique

我有一个桌子栏

CREATE TABLE bar(
  bar_id serial,
  good_bar boolean,
  PRIMARY KEY (bar_id) );

和一个表foo

CREATE TABLE foo (
  foo_id serial,
  side_a INTEGER REFERENCES bar(bar_id),
  side_b INTEGER REFERENCES bar(bar_id) 
  PRIMARY KEY (foo_id); 

但是,一旦在foo.side_a中使用了“ bar”条目,我想防止在foo.side_b中使用它,反之亦然。

PostgreSQL CHECK约束似乎仅限于约束所在的列,并且复合主键(side_a,side_b)不提供类似

的覆盖范围
INSERT INTO foo(side_a,side_b) VALUES
(0, 1),
(1, 0);

我想提出某种错误。

我知道我应该能够使用功能+触发器来检查插入或更新,但是想知道是否没有更简单的解决方案,或者我是否会错误地解决该问题。

编辑以进行澄清: 对于bar_id引用只有一列的问题是,bar表中的数据将根据分配给bar_id的哪一侧进行转换(在数据库外部)。

我能想到的最好的比喻是棋子。双方都有相同的片段,但是从白色(side_a)的角度和黑色(side_b)的角度都可以考虑这些片段的位置。

还有更多实现细节,这些细节依赖于数据的两个不同视角的存在。

1 个答案:

答案 0 :(得分:1)

您需要在表达式上具有唯一索引:

CREATE UNIQUE INDEX ON foo (greatest(side_a, side_b), least(side_a, side_b));

INSERT INTO foo(side_a,side_b) 
VALUES
    (1, 2),
    (2, 1);

ERROR:  duplicate key value violates unique constraint "foo_greatest_least_idx"
DETAIL:  Key ((GREATEST(side_a, side_b)), (LEAST(side_a, side_b)))=(2, 1) already exists.