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:
- Encuentre el nombre de la tabla a la que se hace referencia usando el nombre de tabla, campo y esquema
- Buscar campo referenciado( s) de restricción de clave externa
- ¿Cómo puedo encontrar tablas que hagan referencia a una fila en particular a través de una clave externa?