【问题标题】:How can I use a Postgres EXCLUDE constraint to prevent inserting two primary rows?如何使用 Postgres EXCLUDE 约束来防止插入两个主行?
【发布时间】:2013-06-17 10:21:59
【问题描述】:

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 约束有关吗?有没有更好的方法来做到这一点?

感谢您的帮助!

【问题讨论】:

标签: sql postgresql database-schema


【解决方案1】:

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

create unique index on emails(email) where (primary);

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

【讨论】:

  • 啊,谢谢!这实际上是我最终做的:create unique index on emails(user_id) where ("primary");create unique index on emails(email);
猜你喜欢
  • 2012-12-29
  • 2020-04-15
  • 1970-01-01
  • 2017-08-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-09
  • 2014-04-08
相关资源
最近更新 更多