我有一个表t
,有一个名为 的列json
,类型为JSON
。在 JSON 中有一个自然键:
> SELECT json->'id' AS id FROM t LIMIT 1;
id
-----------------------------
" 63631ff3809de7a17398602f"
我可以创建一个UNIQUE INDEX
on id
,因此:
> CREATE UNIQUE INDEX t_id ON t((json->>'id'));
CREATE INDEX
我想将其添加为table_constraint_using_index,但两者都失败PRIMARY KEY
:
> ALTER TABLE t ADD CONSTRAINT t_pkey PRIMARY KEY USING INDEX t_id;
ERROR: index "t_id" contains expressions
LINE 1: ALTER TABLE t ADD CONSTRAINT t_pkey
^
DETAIL: Cannot create a primary key or unique constraint using such an index.
和UNIQUE
:
> ALTER TABLE t ADD CONSTRAINT t_unique_id UNIQUE USING INDEX t_id;
ERROR: index "t_id" contains expressions
LINE 1: ALTER TABLE t ADD CONSTRAINT t_unique_id...
^
DETAIL: Cannot create a primary key or unique constraint using such an index.
我应该能够添加这样的约束吗?
不,您不应该添加这样的约束。
PRIMARY KEY
必须是简单或复合索引。它可能不是部分索引或表达式索引。索引充当约束,在功能上它们大致相同,但它不能作为
PRIMARY KEY
表元数据中的 出现,也不能用作外键约束的目标。UNIQUE
约束也是如此。这里的问题是
PRIMARY KEY
和UNIQUE
约束的 SQL 标准定义不允许表达式或行匹配谓词。因此,如果 PostgreSQL 将表达式索引或部分索引列为约束,那么它就违反了标准,并向应用程序谎报它在做什么。了解 PostgreSQL 特性的应用可以从 Pg 自己的目录中查找索引,其中也有 infoinformation_schema
,但不能作为列出的约束进入。正如克雷格的回答中所解释的那样,既
PRIMARY KEY
不能也UNIQUE
不能使用。但是,这是解决此问题的两部分解决方案:
要强制执行not null,请使用检查约束,因此:
要强制执行唯一性,请创建唯一索引*,因此:
在此之后,一个
\d t
on inpsql
会给你:您可以看到非空和唯一性都被强制执行:
* 请注意,仅
t_id
索引的存在就足以强制执行唯一性,即使它没有明确地作为约束给出。