Reputation: 1231
I am trying to set a unique constraint on a column that can have an empty JSON object {}
. I am using Postgres 9.6.3.
The problem is that Postgres is treating them as unique because I can insert multiple rows with that same value. I think it is related to how Postgres treats null values as unique. How can I circumvent this?
Upvotes: 0
Views: 2030
Reputation: 1396
You can use a normal unique index treating the json as text. Here is a complete example showing how it works (Corrected):
Create the table:
create table tmp (payload json, name text);
Create our index:
create unique index testindex on tmp ((payload::text), name);
Insert some rows. The first four will work, the rest will fail.
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
If something here isn't working as you expect, please clarify.
Upvotes: 1
Reputation: 2243
You need an another partial index on name when json expression is 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
Upvotes: 1
Reputation: 121604
Use the jsonb
type, a unique constraint works as expected:
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"
Upvotes: 3