sql >> Base de Datos >  >> RDS >> PostgreSQL

Restricción única de Postgres vs índice

Tenía algunas dudas sobre este tema básico pero importante, así que decidí aprender con el ejemplo.

Vamos a crear la tabla de prueba master con dos columnas, con_id con restricción única y ind_id indexado por índice único.

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)

En la descripción de la tabla (\d en psql) puede diferenciar la restricción única del índice único.

Singularidad

Comprobemos la unicidad, por si acaso.

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

¡Funciona como se esperaba!

Claves foráneas

Ahora definiremos detalle tabla con dos claves foráneas que hacen referencia a nuestras dos columnas en 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)

Bueno, sin errores. Asegurémonos de que funcione.

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

Se puede hacer referencia a ambas columnas en claves foráneas.

Restricción mediante índice

Puede agregar restricciones de tabla utilizando el índice único existente.

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)

Ahora no hay diferencia entre la descripción de las restricciones de columna.

Índices parciales

En la declaración de restricción de tabla, no puede crear índices parciales. Viene directamente de la definición de create table ... .En la declaración de índice único, puede establecer la cláusula WHERE clause para crear un índice parcial. También puede crear un índice en la expresión (no solo en la columna) y definir algunos otros parámetros (intercalación, orden de clasificación, ubicación de NULL).

no puedes agregar restricción de tabla usando índice parcial.

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.