如何使一个空的 JSON 对象在 Postgres 中不是唯一的?

How to make an empty JSON object not unique in Postgres?

我正在尝试对可以具有空 JSON 对象 {} 的列设置唯一约束。我正在使用 Postgres 9.6.3。

问题是 Postgres 将它们视为唯一的,因为我可以插入具有相同值的多行。我认为这与 Postgres 如何将 null 值视为唯一有关。我怎样才能避免这种情况?

您可以使用普通的唯一索引将 json 视为文本。这是一个显示其工作原理的完整示例(已更正):

创建 table: create table tmp (payload json, name text);

创建我们的索引: create unique index testindex on tmp ((payload::text), name);

插入一些行。前四个会起作用,其余的会失败。

insert into tmp (payload, name) values ('{}', 'foo');
// Succeeds
insert into tmp (payload, name) values ('{}', 'bar');
// Succeeds
insert into tmp (payload, name) values ('{"a":"b"}'::json, 'foo');
// Succeeds
insert into tmp (payload, name) values ('{"a":"b"}'::json, 'bar');
// Succeeds
insert into tmp (payload, name) values ('{"a":"b"}'::json, 'foo');
// Fails due to index
insert into tmp (payload, name) values ('{}', 'bar');
// Fails due to index

如果这里的某些地方没有按您预期的那样工作,请澄清。

使用 jsonb 类型,唯一约束按预期工作:

create table my_table(
    id serial primary key, 
    jdata jsonb unique
);

insert into my_table (jdata) 
values
    ('{}'),
    ('{}');

ERROR:  duplicate key value violates unique constraint "my_table_jdata_key"

当 json 表达式为 null

时,您需要名称的另一个部分索引
CREATE TABLE action (
  id BIGSERIAL PRIMARY KEY, 
  name text,
  payload json
);

create unique INDEX actions_constraint on action (((payload#>>'{message, payload, content}')::text), name);

insert into action(name,payload) values ('a','{}');--works
insert into action(name,payload) values ('a','{}');--works

create unique INDEX actions_constraint_on_empty on action (name) where (payload::text = '{}');
--fails
truncate action;

create unique INDEX actions_constraint_on_empty on action (name) where (payload::text = '{}');
--works

insert into action(name,payload) values ('a','{}');
--works
insert into action(name,payload) values ('a','{}');
--fails

勾选https://dba.stackexchange.com/questions/9759/postgresql-multi-column-unique-constraint-and-null-values