Postgres 9.0支持排除约束,它类似于一般的唯一约束(http://www.postgresql.org/docs/9.0/static/sql-createtable.html#SQL-CREATETABLE-EXCLUDE)。
我认为这可能是解决此问题的好方法,但我无法弄清楚如何正确使用排除约束。
这是问题所在: 我有一张这样的桌子:
CREATE TABLE emails (
id integer NOT NULL,
email character varying(255),
"primary" boolean DEFAULT false,
user_id integer,
);
我想确保每个唯一user_id
只有一行"primary"
等于true。我尝试使用这样的排除约束:
ALTER TABLE emails ADD CONSTRAINT one_primary_email_per_user EXCLUDE USING gist (user_id WITH =, "primary" WITH &);
Postgres拒绝了:
ERROR: data type boolean has no default operator class for access method "gist"
HINT: You must specify an operator class for the index or define a default operator class for the data type.
我再次尝试将布尔列转换为bit
:
ALTER TABLE emails ADD CONSTRAINT one_primary_email_per_user EXCLUDE (user_id WITH =, (case "primary" when 't' then '1'::bit else '0'::bit end) WITH &);
那不起作用。似乎&(bit,bit)
不是运算符类bit_ops
的一部分:
ERROR: operator &(bit,bit) is not a member of operator family "bit_ops"
DETAIL: The exclusion operator must be related to the index operator class for the constraint.
查看http://www.leadum.com/downloads/dbscribe/samples/postgresql/web_modern/opclass/main/790197862.html,似乎bit_ops
只包含排序比较运算符(>,<,=,> =,< =)而不包括按位运算符。我不确定为什么会这样。
这种排除是否可以通过EXCLUDE约束进行?有更好的方法吗?
感谢您的帮助!
答案 0 :(得分:12)
为此创建部分唯一索引应该更简单:
create unique index on emails(email) where (primary);
(与此答案正交,但由于您询问错误消息:对于排除约束,您需要添加btree_gin
或btree_gist
扩展名以供btree运算符使用。 )