Avevo qualche dubbio su questo problema fondamentale ma importante, quindi ho deciso di imparare dall'esempio.
Creiamo tabella di test maestro con due colonne, con_id con vincolo univoco e ind_id indicizzati da indice univoco.
create table master (
con_id integer unique,
ind_id integer
);
create unique index master_unique_idx on master (ind_id);
Table "public.master"
Column | Type | Modifiers
--------+---------+-----------
con_id | integer |
ind_id | integer |
Indexes:
"master_con_id_key" UNIQUE CONSTRAINT, btree (con_id)
"master_unique_idx" UNIQUE, btree (ind_id)
In descrizione della tabella (\ d in psql) si può dire vincolo univoco da indice univoco.
controllo unicità Unicità
Let, per ogni evenienza.
test=# insert into master values (0, 0);
INSERT 0 1
test=# insert into master values (0, 1);
ERROR: duplicate key value violates unique constraint "master_con_id_key"
DETAIL: Key (con_id)=(0) already exists.
test=# insert into master values (1, 0);
ERROR: duplicate key value violates unique constraint "master_unique_idx"
DETAIL: Key (ind_id)=(0) already exists.
test=#
Funziona come previsto!
chiavi esterne
Ora definiremo dettaglio tavolo con due chiavi esterne riferimento ai nostri due colonne in maestro.
create table detail (
con_id integer,
ind_id integer,
constraint detail_fk1 foreign key (con_id) references master(con_id),
constraint detail_fk2 foreign key (ind_id) references master(ind_id)
);
Table "public.detail"
Column | Type | Modifiers
--------+---------+-----------
con_id | integer |
ind_id | integer |
Foreign-key constraints:
"detail_fk1" FOREIGN KEY (con_id) REFERENCES master(con_id)
"detail_fk2" FOREIGN KEY (ind_id) REFERENCES master(ind_id)
Bene, nessun errore. Assicuriamoci che funzioni.
test=# insert into detail values (0, 0);
INSERT 0 1
test=# insert into detail values (1, 0);
ERROR: insert or update on table "detail" violates foreign key constraint "detail_fk1"
DETAIL: Key (con_id)=(1) is not present in table "master".
test=# insert into detail values (0, 1);
ERROR: insert or update on table "detail" violates foreign key constraint "detail_fk2"
DETAIL: Key (ind_id)=(1) is not present in table "master".
test=#
Entrambe le colonne possono essere referenziate in chiavi esterne.
vincolo utilizzando indice
È possibile aggiungere vincolo di tabella con indice univoco esistente.
alter table master add constraint master_ind_id_key unique using index master_unique_idx;
Table "public.master"
Column | Type | Modifiers
--------+---------+-----------
con_id | integer |
ind_id | integer |
Indexes:
"master_con_id_key" UNIQUE CONSTRAINT, btree (con_id)
"master_ind_id_key" UNIQUE CONSTRAINT, btree (ind_id)
Referenced by:
TABLE "detail" CONSTRAINT "detail_fk1" FOREIGN KEY (con_id) REFERENCES master(con_id)
TABLE "detail" CONSTRAINT "detail_fk2" FOREIGN KEY (ind_id) REFERENCES master(ind_id)
Ora non c'è differenza tra la descrizione dei vincoli di colonna.
indici parziali
In tabella di dichiarazione di vincolo non è possibile creare indici parziali. Viene direttamente dallo definition di create table ...
. Nella dichiarazione indice univoca è possibile impostare WHERE clause
per creare un indice parziale. È anche possibile create index all'espressione (non solo sulla colonna) e definire altri parametri (fascicolazione, ordinamento, posizionamento NULL).
Non è possibile aggiungere un vincolo di tabella utilizzando l'indice parziale.
alter table master add column part_id integer;
create unique index master_partial_idx on master (part_id) where part_id is not null;
alter table master add constraint master_part_id_key unique using index master_partial_idx;
ERROR: "master_partial_idx" is a partial index
LINE 1: alter table master add constraint master_part_id_key unique ...
^
DETAIL: Cannot create a primary key or unique constraint using such an index.
L'(solo) differenza pratica è che si può creare una chiave esterna per un vincolo univoco, ma non a un indice univoco. –
Un vantaggio al contrario ([come riportato in un'altra domanda di recente] (http://stackoverflow.com/a/23449309/157957) è che puoi avere un indice univoco * parziale *, come "Unico (foo) Dove bar è Null ". AFAIK, non c'è modo di farlo con un vincolo. – IMSoP
[Here] (http://flatiron.engineering/technology/2016/09/13/uniqueness-in-postgres.html) bel articolo sulla differenza –