Impostazione di prova
Si assume il nome del vincolo test_def_abc_id_fkey
, il nome predefinito risultante dalla tua configurazione in Postgres 11 o versioni precedenti. Vale la pena notare, tuttavia, che i nomi predefiniti sono stati migliorati per Postgres 12, dove la stessa configurazione risulta in test_def_abc_id_abc_id2_fkey
. Le note di rilascio per Postgres 12:
Vedi:
db<>violino qui
Quindi usiamo il nome esplicito test_def_abc_fkey
per il vincolo FK per evitare confusione:
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)
);
E che funziona in Postgres 9.5 - Postgres 12.
Anche in Postgres 9.3.
(Ho avuto l'impressione sbagliata di un effettivo vincolo sarebbe necessario.)
Risposta
La tua osservazione dall'interrogazione dello schema di informazioni vale:
SELECT *
FROM information_schema.referential_constraints
WHERE constraint_name = 'test_def_abc_fkey'; -- unequivocal name
Otteniamo una riga, ma i tre campi unique_constraint_catalog
, unique_constraint_schema
e unique_constraint_name
sono NULL
.
La spiegazione sembra semplice. Quelle colonne descrivono, come dice il manuale:
Ma non esiste UNIQUE
vincolo
, solo un UNIQUE
indice
. Un UNIQUE
il vincolo è implementato usando un UNIQUE
indice in Postgres. I vincoli sono definiti dallo standard SQL, gli indici sono dettagli di implementazione. Ci sono differenze come quella che hai scoperto. Correlati:
Lo stesso test con un vero UNIQUE
vincolo mostra i dati come previsto:
db<>violino qui
Quindi questo sembra avere senso. Soprattutto perché lo schema informativo è anche definito dal comitato per gli standard SQL e gli indici non sono standardizzati, ma solo vincoli. (Nessuna informazione sull'indice nelle viste dello schema delle informazioni.)
Tutto chiaro? Non proprio.
Comunque
Esiste un'altra visualizzazione dello schema di informazioni key_column_usage
. La sua ultima colonna è descritta come:
Grassetto enfasi mia. Qui, la posizione ordinale della colonna nell'indice è comunque elencato:
SELECT *
FROM information_schema.key_column_usage
WHERE constraint_name = 'test_def_abc_fkey';
Vedi:
db<>violino qui
Sembra incoerente.
Quel che è peggio, il manuale
afferma che una vera e propria PRIMARY KEY
o UNIQUE
sarebbe richiesto un vincolo per la creazione di una FOREIGN KEY
vincolo:
Sembra essere un bug di documentazione ? Se nessuno può indicare dove sbaglio qui, presenterò una segnalazione di bug.
Correlati:
Soluzione
In Postgres, il catalogo di sistema è la vera fonte di verità. Vedi:
Quindi potresti usare qualcosa del genere (come ho anche aggiunto nel violino sopra):
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';
Resi:
conname | fk_table | fk_columns | ref_table | ref_key_columns :---------------- | :------- | :--------------- | :-------- | :-------------- test_def_abc_fkey | test_def | {abc_id,abc_id2} | test_abc | {id,id2}
Correlati:
- Trova il nome della tabella di riferimento utilizzando la tabella, il campo e il nome dello schema
- Trova campo referenziato( s) di vincolo di chiave esterna
- Come posso trovare tabelle che fanno riferimento a una determinata riga tramite una chiave esterna?