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

Valores NULL para las columnas referencial_constraints.unique_constraint_* en el esquema de información

Configuración de prueba

Asume el nombre de restricción test_def_abc_id_fkey , el nombre predeterminado resultante de su configuración en Postgres 11 o anterior. Sin embargo, vale la pena señalar que los nombres predeterminados se han mejorado para Postgres 12, donde la misma configuración da como resultado test_def_abc_id_abc_id2_fkey . Las notas de la versión de Postgres 12:

Ver:

db<>fiddle aquí

Así que usemos el nombre explícito test_def_abc_fkey para la restricción FK para evitar confusiones:

CREATE TABLE test_abc (
  pk  int PRIMARY KEY
, id  int NOT NULL
, id2 int NOT NULL
);

CREATE UNIQUE INDEX test_abc_ids ON test_abc(id,id2);

CREATE TABLE test_def (
  id      int PRIMARY KEY
, abc_id  int
, abc_id2 int
, CONSTRAINT test_def_abc_fkey  -- !
     FOREIGN KEY (abc_id,abc_id2) REFERENCES test_abc(id,id2)
);

Y eso funciona en Postgres 9.5 - Postgres 12.
Incluso en Postgres 9.3.
(Tenía una impresión equivocada de una limitación real sería necesario.)

Respuesta

Su observación de consultar el esquema de información contiene:

SELECT *
FROM   information_schema.referential_constraints
WHERE  constraint_name = 'test_def_abc_fkey';  -- unequivocal name

Obtenemos una fila, pero los tres campos unique_constraint_catalog , unique_constraint_schema y unique_constraint_name son NULL .

La explicación parece sencilla. Esas columnas describen, como dice el manual:

Pero no hay UNIQUE restricción , solo un UNIQUE índice . UN UNIQUE la restricción se implementa usando un UNIQUE índice en Postgres. Las restricciones están definidas por el estándar SQL, los índices son detalles de implementación. Hay diferencias como la que descubriste. Relacionado:

La misma prueba con un UNIQUE real restricción muestra los datos como se esperaba:

db<>fiddle aquí

Así que esto parece tener sentido. Especialmente desde el esquema de información también está definido por el comité de estándares de SQL y los índices no están estandarizados, solo restricciones. (No hay información de índice en las vistas del esquema de información).

¿Todo claro? No del todo.

Sin embargo

Hay otra vista de esquema de información key_column_usage . Su última columna se describe como:

Negrita énfasis mío. Aquí, la posición ordinal de la columna en el índice aparece de todos modos:

SELECT *
FROM   information_schema.key_column_usage
WHERE  constraint_name = 'test_def_abc_fkey';

Ver:

db<>fiddle aquí

Parece inconsistente.

Lo que es peor, el manual afirma que una PRIMARY KEY real o UNIQUE se requeriría una restricción para la creación de una FOREIGN KEY restricción:

Parece ser un error de documentación ? Si nadie puede señalar dónde me estoy equivocando aquí, presentaré un informe de error.

Relacionado:

Solución

En Postgres, el catálogo del sistema es la fuente real de la verdad. Ver:

Entonces podría usar algo como esto (como también agregué en el fiddle arriba):

SELECT c.conname
     , c.conrelid::regclass  AS fk_table, k1.fk_columns
     , c.confrelid::regclass AS ref_table, k2.ref_key_columns
FROM   pg_catalog.pg_constraint c
LEFT   JOIN LATERAL (
   SELECT ARRAY (
      SELECT a.attname
      FROM   pg_catalog.pg_attribute a
           , unnest(c.conkey) WITH ORDINALITY AS k(attnum, ord)
      WHERE  a.attrelid = c.conrelid
      AND    a.attnum = k.attnum
      ORDER  BY k.ord
      ) AS fk_columns
   ) k1 ON true
LEFT   JOIN LATERAL (
   SELECT ARRAY (
      SELECT a.attname
      FROM   pg_catalog.pg_attribute a
           , unnest(c.confkey) WITH ORDINALITY AS k(attnum, ord)
      WHERE  a.attrelid = c.confrelid
      AND    a.attnum = k.attnum
      ORDER  BY k.ord
      ) AS ref_key_columns
   ) k2 ON true
WHERE  conname = 'test_def_abc_fkey';

Devoluciones:

conname           | fk_table | fk_columns       | ref_table | ref_key_columns
:---------------- | :------- | :--------------- | :-------- | :--------------
test_def_abc_fkey | test_def | {abc_id,abc_id2} | test_abc  | {id,id2}       

Relacionado: