PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Contrainte unique Postgres vs index

J'avais des doutes sur ce problème fondamental mais important, alors j'ai décidé d'apprendre par l'exemple.

Créons la table de test maître avec deux colonnes, con_id avec contrainte unique et ind_id indexé par index unique.

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)

Dans la description de la table (\d dans psql), vous pouvez distinguer la contrainte unique de l'index unique.

Unicité

Vérifions l'unicité, juste au cas où.

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=#

Cela fonctionne comme prévu !

Clés étrangères

Nous allons maintenant définir détail table avec deux clés étrangères faisant référence à nos deux colonnes dans master .

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)

Eh bien, pas d'erreurs. Assurons-nous que cela fonctionne.

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=#

Les deux colonnes peuvent être référencées dans des clés étrangères.

Contrainte utilisant l'index

Vous pouvez ajouter une contrainte de table à l'aide d'un index unique existant.

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)

Désormais, il n'y a plus de différence entre la description des contraintes de colonne.

Index partiels

Dans la déclaration de contrainte de table, vous ne pouvez pas créer d'index partiels. Cela vient directement de la définition de create table ... .Dans la déclaration d'index unique, vous pouvez définir la WHERE clause pour créer un index partiel. Vous pouvez également créer un index sur l'expression (pas seulement sur la colonne) et définir d'autres paramètres (collation, ordre de tri, placement des NULL).

Vous ne pouvez pas ajouter une contrainte de table à l'aide d'un index partiel.

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.