如何使用Postgres EXCLUDE约束来防止插入两个主要行?

And*_*ler 5 sql postgresql database-schema

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,
 );
Run Code Online (Sandbox Code Playgroud)

我想确保每个独特的只有一行user_id"primary"等于真.我尝试使用这样的排除约束:

 ALTER TABLE emails ADD CONSTRAINT one_primary_email_per_user EXCLUDE USING gist (user_id WITH =, "primary" WITH &);
Run Code Online (Sandbox Code Playgroud)

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.
Run Code Online (Sandbox Code Playgroud)

我再次尝试将布尔列转换为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 &);
Run Code Online (Sandbox Code Playgroud)

那没用.它似乎&(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.
Run Code Online (Sandbox Code Playgroud)

查看http://www.leadum.com/downloads/dbscribe/samples/postgresql/web_modern/opclass/main/790197862.html,似乎bit_ops只包括排序比较运算符(>,<,=,> =,<= )而不是按位运算符.我不确定为什么会这样.

这种排除是否可以通过EXCLUDE约束进行?有一个更好的方法吗?

谢谢您的帮助!

Den*_*rdy 12

为此创建一个部分唯一索引应该更简单:

create unique index on emails(email) where (primary);
Run Code Online (Sandbox Code Playgroud)

(与此答案正交,但由于您询问错误消息:对于排除约束,您需要添加btree_ginbtree_gist扩展以与btree运算符一起使用.)

  • 啊,谢谢!这实际上是我最终要做的事情:`在电子邮件上创建唯一索引(user_id),其中("primary");`和`在电子邮件上创建唯一索引(电子邮件);`. (2认同)