Configuration du test
Vous assumez le nom de la contrainte test_def_abc_id_fkey
, le nom par défaut résultant de votre configuration dans Postgres 11 ou une version antérieure. Il convient de noter, cependant, que les noms par défaut ont été améliorés pour Postgres 12, où la même configuration aboutit à test_def_abc_id_abc_id2_fkey
. Les notes de version de Postgres 12 :
Voir :
db<>violon ici
Utilisons donc le nom explicite test_def_abc_fkey
pour la contrainte FK afin d'éviter toute confusion :
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)
);
Et cela fonctionne dans Postgres 9.5 - Postgres 12.
Même dans Postgres 9.3.
(J'avais eu la mauvaise impression d'une réelle contrainte serait nécessaire.)
Répondre
Votre observation en interrogeant le schéma d'information tient :
SELECT *
FROM information_schema.referential_constraints
WHERE constraint_name = 'test_def_abc_fkey'; -- unequivocal name
Nous obtenons une ligne, mais les trois champs unique_constraint_catalog
, unique_constraint_schema
et unique_constraint_name
sont NULL
.
L'explication paraît simple. Ces colonnes décrivent, comme le dit le manuel :
Mais il n'y a pas de UNIQUE
contrainte
, juste un UNIQUE
index
. Un UNIQUE
contrainte est implémentée en utilisant un UNIQUE
index dans Postgres. Les contraintes sont définies par le standard SQL, les index sont des détails d'implémentation. Il existe des différences comme celle que vous avez découverte. Connexe :
Le même test avec un réel UNIQUE
contrainte affiche les données comme prévu :
db<>violon ici
Cela semble donc logique. D'autant plus que le schéma d'information est également défini par le comité des normes SQL et les index ne sont pas standardisés, seulement des contraintes. (Aucune information d'index dans les vues de schéma d'information.)
Tout est clair? Pas tout à fait.
Cependant
Il existe une autre vue de schéma d'informations key_column_usage
. Sa dernière colonne est décrite comme :
Gras l'accent est mis sur le mien. Ici, la position ordinale de la colonne dans l'index est répertorié de toute façon :
SELECT *
FROM information_schema.key_column_usage
WHERE constraint_name = 'test_def_abc_fkey';
Voir :
db<>violon ici
Semble incohérent.
Pire encore, le manuel
prétend qu'une PRIMARY KEY
réelle ou UNIQUE
contrainte serait nécessaire pour la création d'une FOREIGN KEY
contrainte :
Semble être un bogue de documentation ? Si personne ne peut indiquer où je me trompe ici, je déposerai un rapport de bogue.
Connexe :
Solution
Dans Postgres, le catalogue système est la véritable source de vérité. Voir :
Vous pouvez donc utiliser quelque chose comme ça (comme j'ai aussi ajouté dans le violon ci-dessus):
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';
Renvoie :
conname | fk_table | fk_columns | ref_table | ref_key_columns :---------------- | :------- | :--------------- | :-------- | :-------------- test_def_abc_fkey | test_def | {abc_id,abc_id2} | test_abc | {id,id2}
Connexe :
- Recherchez le nom de la table référencée à l'aide du nom de la table, du champ et du schéma
- Rechercher le champ référencé( s) de contrainte de clé étrangère
- Comment puis-je trouver des tables qui référencent une ligne particulière via une clé étrangère ?