我想設置一個唯一的約束可以有一個空的JSON對象的列{}
。我正在使用Postgres 9.6.3。如何使一個空的JSON對象在Postgres中不唯一?
問題是,Postgres將它們視爲獨一無二的,因爲我可以插入具有相同值的多行。我認爲這與Postgres如何將空值視爲唯一對象有關。我怎樣才能繞過這個?
我想設置一個唯一的約束可以有一個空的JSON對象的列{}
。我正在使用Postgres 9.6.3。如何使一個空的JSON對象在Postgres中不唯一?
問題是,Postgres將它們視爲獨一無二的,因爲我可以插入具有相同值的多行。我認爲這與Postgres如何將空值視爲唯一對象有關。我怎樣才能繞過這個?
您可以使用正常的唯一索引,將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
如果這裏的某些內容不能按照您的預期工作,請澄清。
使用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"
謝謝,這也適用。但是,這需要更改數據類型,因此它看起來需要稍微更多的工作來遷移和種子數據。所以鑑於我只能選擇一個答案,我將@cske答案標記爲正確。我現在也有點害怕改變數據類型,以防我破壞其餘的代碼庫。 – writofmandamus
我理解你對改變數據類型的擔憂,儘管它非常簡單而且相當安全。如果您需要列上的索引,那麼使用jsonb是特別需要的。另請參閱[PostgreSQL引入的JSONB的說明](https://stackoverflow.com/a/22910602/1995738)和[何時使用Postgres中的非結構化數據類型](https://www.citusdata.com/blog/2016/ 7月14日/選擇的NoSQL-hstore-JSON-jsonb /)。 – klin
當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
謝謝,這看起來像一個很好的答案。我希望更明確地說,'payload'等於'{}'時。這是如何構建的?這是不被接受的:'在動作(名稱)上創建唯一的INDEX actions_constraint_on_empty,其中payload =='{}';'。我猜我需要一些運算符'有效載荷',所以它被視爲JSON? – writofmandamus
等待,這可能是因爲我在'有效負載'周圍遺漏了括號。 – writofmandamus
'=='??使用'=' – cske
這確實需要一個對名稱的另一個部分索引不工作,更具體地說,我將它設置爲在兩列組合中是唯一的:「創建唯一的INDEX actions_constraint on actions(((payload#>>'{message,有效載荷,內容}'):: text),name)有效載荷!='{}';'我的兩列名稱是'有效載荷'和'名稱', – writofmandamus
它們是否都是實際文本字段?如果是這樣,那麼它應該工作得很好,它對我來說只是一個簡單的臨時/測試表。 – alzee
'payload'是類型'json','name'是類型'text'。但是,有效載荷 - >消息 - >有效載荷 - >>內容將被鍵入「文本」。但是,我們需要處理創建如下行的情況:'name:sometext'和payload:'{}''。 – writofmandamus