Tenho uma tabela t
, com uma coluna chamada json
, do tipo JSON
. Dentro do JSON existe uma chave natural :
> SELECT json->'id' AS id FROM t LIMIT 1;
id
-----------------------------
" 63631ff3809de7a17398602f"
Posso criar um UNIQUE INDEX
on id
, assim:
> CREATE UNIQUE INDEX t_id ON t((json->>'id'));
CREATE INDEX
Eu gostaria de adicionar isso como um table_constraint_using_index , mas falha para ambos PRIMARY KEY
:
> ALTER TABLE t ADD CONSTRAINT t_pkey PRIMARY KEY USING INDEX t_id;
ERROR: index "t_id" contains expressions
LINE 1: ALTER TABLE t ADD CONSTRAINT t_pkey
^
DETAIL: Cannot create a primary key or unique constraint using such an index.
e UNIQUE
:
> ALTER TABLE t ADD CONSTRAINT t_unique_id UNIQUE USING INDEX t_id;
ERROR: index "t_id" contains expressions
LINE 1: ALTER TABLE t ADD CONSTRAINT t_unique_id...
^
DETAIL: Cannot create a primary key or unique constraint using such an index.
Devo ser capaz de adicionar tal restrição?
Não, você não deve ser capaz de adicionar tal restrição.
O
PRIMARY KEY
deve ser um índice simples ou composto. Pode não ser um índice parcial ou de expressão.O índice atua como uma restrição e, funcionalmente, é praticamente o mesmo, mas não pode aparecer como
PRIMARY KEY
nos metadados da tabela e não pode ser usado como o destino de uma restrição de chave estrangeira. O mesmo vale para asUNIQUE
restrições.PRIMARY KEY
O problema aqui é que as definições e restrições do padrão SQLUNIQUE
não permitem expressões ou predicados de correspondência de linha. Portanto, se o PostgreSQL listar um índice de expressão ou índice parcial como uma restrição, ele está quebrando o padrão e mentindo para os aplicativos sobre o que está fazendo. Os aplicativos que entendem os recursos do PostgreSQL podem procurar o índice nos próprios catálogos do Pg e também há informações eminformation_schema
, mas não podem entrar como uma restrição listada.Conforme explicado na resposta de Craig, nem
PRIMARY KEY
nemUNIQUE
pode ser usado.No entanto, aqui está uma solução em duas partes para contornar isso:
Para impor not null , use uma restrição de verificação , assim:
Para impor exclusividade , crie um índice exclusivo*, assim:
Depois disso, um
\d t
on inpsql
lhe dará:E você pode ver que não nulos e exclusivos são aplicados:
* observe que a mera existência do
t_id
índice é suficiente para impor a exclusividade, mesmo que não seja explicitamente fornecida como uma restrição.