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

时间:2017-08-09 17:52:03

标签: json postgresql unique-constraint

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

问题在于Postgres将它们视为唯一,因为我可以插入具有相同值的多个行。我认为这与Postgres如何将空值视为唯一有关。我怎么能绕过这个?

3 个答案:

答案 0 :(得分:3)

使用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"

答案 1 :(得分:1)

您可以使用将json视为文本的常规唯一索引。这是一个完整的示例,显示它是如何工作的(更正):

创建表格: 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

如果此处的某些内容无法按预期运行,请澄清。

答案 2 :(得分:1)

当json表达式为空时,您需要另一个名称的部分索引

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