2017-08-09 42 views
0

我想設置一個唯一的約束可以有一個空的JSON對象的列{}。我正在使用Postgres 9.6.3。如何使一個空的JSON對象在Postgres中不唯一?

問題是,Postgres將它們視爲獨一無二的,因爲我可以插入具有相同值的多行。我認爲這與Postgres如何將空值視爲唯一對象有關。我怎樣才能繞過這個?

回答

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 

如果這裏的某些內容不能按照您的預期工作,請澄清。

+0

這確實需要一個對名稱的另一個部分索引不工作,更具體地說,我將它設置爲在兩列組合中是唯一的:「創建唯一的INDEX actions_constraint on actions(((payload#>>'{message,有效載荷,內容}'):: text),name)有效載荷!='{}';'我的兩列名稱是'有效載荷'和'名稱', – writofmandamus

+0

它們是否都是實際文本字段?如果是這樣,那麼它應該工作得很好,它對我來說只是一個簡單的臨時/測試表。 – alzee

+0

'payload'是類型'json','name'是類型'text'。但是,有效載荷 - >消息 - >有效載荷 - >>內容將被鍵入「文本」。但是,我們需要處理創建如下行的情況:'name:sometext'和payload:'{}''。 – writofmandamus

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" 
+0

謝謝,這也適用。但是,這需要更改數據類型,因此它看起來需要稍微更多的工作來遷移和種子數據。所以鑑於我只能選擇一個答案,我將@cske答案標記爲正確。我現在也有點害怕改變數據類型,以防我破壞其餘的代碼庫。 – writofmandamus

+1

我理解你對改變數據類型的擔憂,儘管它非常簡單而且相當安全。如果您需要列上的索引,那麼使用jsonb是特別需要的。另請參閱[PostgreSQL引入的JSONB的說明](https://stackoverflow.com/a/22910602/1995738)和[何時使用Postgres中的非結構化數據類型](https://www.citusdata.com/blog/2016/ 7月14日/選擇的NoSQL-hstore-JSON-jsonb /)。 – klin

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

+0

謝謝,這看起來像一個很好的答案。我希望更明確地說,'payload'等於'{}'時。這是如何構建的?這是不被接受的:'在動作(名稱)上創建唯一的INDEX actions_constraint_on_empty,其中payload =='{}';'。我猜我需要一些運算符'有效載荷',所以它被視爲JSON? – writofmandamus

+0

等待,這可能是因爲我在'有效負載'周圍遺漏了括號。 – writofmandamus

+0

'=='??使用'=' – cske

相關問題