PostgreSQL唯一值ACREOS多列

PostgreSQL唯一值ACREOS多列,postgresql,constraints,unique,Postgresql,Constraints,Unique,我有一个PostgreSQL表 id ColA ColB ------------------ 1 'a' 'b' 2 'c' 'd' 我想使ColA和ColB中的值在两列中都是唯一的,即禁止任何插入: INSERT INTO table (ColA,ColB) values('a','e'); INSERT INTO table (ColA,ColB) values('z','a'); INSERT INTO table (ColA,ColB) v

我有一个PostgreSQL表

id    ColA    ColB
------------------
1     'a'     'b'
2     'c'     'd'
我想使ColA和ColB中的值在两列中都是唯一的,即禁止任何插入:

INSERT INTO table (ColA,ColB) values('a','e');
INSERT INTO table (ColA,ColB) values('z','a');
INSERT INTO table (ColA,ColB) values('d','g');
任何此类插入都是允许的:

INSERT INTO table (ColA,ColB) values('z','e');
INSERT INTO table (ColA,ColB) values('l','k');
所以


不适合,因为它将允许前面4个插入中的任何一个。

遗憾的是,这不能用简单的唯一约束/索引轻松解决(如果可以用它们解决的话)

您需要的是:基于诸如碰撞之类的内容排除某些行的能力。唯一约束只是特定的排除约束(它们基于相等冲突)

因此,从理论上讲,您只需要排除每个
row1
,其中已经有一个
row2
,对于这个表达式:
ARRAY[row1.cola,row1.colb]&&ARRAY[row2.cola,row2.colb]

此索引可以执行此任务(目前只有
gist
索引支持排除约束):

但是不幸的是,数组没有默认的操作符类(使用
gist
)。有一个,它只为
整数
数组提供一个,而不为
文本
数组提供一个

如果你真的想解决这个问题,你总是可以滥用(例如,我使用了相邻的
-|-
操作符,它处理所有的情况,而
unique
无法处理这些情况)


。。。但我担心,通过一点数据库重构,您原来的问题可能会更容易解决;这就引出了一个问题:您想用它解决什么问题?

我有一个类似的问题:用户表有两列电子邮件地址。一封用于普通电子邮件,另一封用于未经验证的新电子邮件。现在我希望它们是唯一的,不管它们是否已经被验证过。
CONSTRAINT unique_name UNIQUE (ColA,ColB)
ALTER TABLE table_name
  ADD CONSTRAINT table_name_exclusion
  EXCLUDE USING gist ((ARRAY[cola, colb]) WITH &&);
-- there is no built-in type for text ranges neither,
-- but it can can be created fairly easily:
CREATE TYPE textrange AS RANGE (
  SUBTYPE = text
);

ALTER TABLE table_name
  ADD CONSTRAINT table_name_exclusion
  EXCLUDE USING gist ((textrange(least(cola, colb), greatest(cola, colb))) WITH -|-);

-- the exclusion constraint above does not handle all situations:

ALTER TABLE table_name
  ADD CONSTRAINT table_name_check
  CHECK (cola is distinct from colb); -- without this, empty ranges could be created,
                                      -- which are not adjacent to any other range

CREATE UNIQUE INDEX table_name_unique
  ON table_name ((ARRAY[least(cola, colb), greatest(cola, colb)]));
     -- without this, duplicated rows could be created,
     -- because ranges are not adjacent to themselves