Test opsætning
Du antager begrænsningsnavnet test_def_abc_id_fkey
, standardnavnet som følge af din opsætning i Postgres 11 eller ældre. Det er dog værd at bemærke, at standardnavne er blevet forbedret for Postgres 12, hvor den samme opsætning resulterer i test_def_abc_id_abc_id2_fkey
. Udgivelsesbemærkningerne til Postgres 12:
Se:
db<>fiddle her
Så lad os bruge det eksplicitte navn test_def_abc_fkey
for FK-begrænsningen for at undgå forvirring:
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)
);
Og at virker i Postgres 9.5 - Postgres 12.
Selv i Postgres 9.3.
(Jeg havde et forkert indtryk af en faktisk begrænsning ville være påkrævet.)
Svar
Din observation ved at forespørge informationsskemaet gælder:
SELECT *
FROM information_schema.referential_constraints
WHERE constraint_name = 'test_def_abc_fkey'; -- unequivocal name
Vi får en række, men de tre felter unique_constraint_catalog
, unique_constraint_schema
og unique_constraint_name
er NULL
.
Forklaringen virker simpel. Disse kolonner beskriver, som manualen udtrykker det:
Men der er ingen UNIQUE begrænsning
, bare en UNIQUE
indeks
. En UNIQUE
begrænsning er implementeret ved hjælp af en UNIQUE
indeks i Postgres. Begrænsninger er defineret af SQL-standarden, indekser er implementeringsdetaljer. Der er forskelle som den, du opdagede. Relateret:
Den samme test med en faktisk UNIQUE
begrænsning viser data som forventet:
db<>fiddle her
Så det ser ud til at give mening. Især siden informationsskemaet er også defineret af SQL-standardudvalget, og indekser er ikke standardiserede, kun begrænsninger. (Ingen indeksoplysninger i informationsskemavisninger.)
Fri bane? Ikke helt.
Men
Der er en anden informationsskemavisning key_column_usage
. Dens sidste kolonne er beskrevet som:
Fed vægt min. Her er rækkefølgen af kolonnen i indekset er angivet alligevel:
SELECT *
FROM information_schema.key_column_usage
WHERE constraint_name = 'test_def_abc_fkey';
Se:
db<>fiddle her
Virker inkonsekvent.
Hvad værre er, manualen
hævder, at en faktisk PRIMÆR NØGLE
eller UNIQUE
begrænsning ville være påkrævet for at oprette en FREIGN KEY
begrænsning:
Ser ud til at være en dokumentationsfejl ? Hvis ingen kan påpege, hvor jeg tager fejl her, indsender jeg en fejlrapport.
Relateret:
Løsning
I Postgres er systemkataloget den egentlige kilde til sandheden. Se:
Så du kunne bruge sådan noget (som jeg også tilføjede i violen ovenfor):
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';
Returnerer:
conname | fk_table | fk_columns | ref_table | ref_key_columns :---------------- | :------- | :--------------- | :-------- | :-------------- test_def_abc_fkey | test_def | {abc_id,abc_id2} | test_abc | {id,id2}
Relateret:
- Find det refererede tabelnavn ved hjælp af tabel-, felt- og skemanavn
- Find refereret felt( s) af fremmednøglebegrænsning
- Hvordan kan jeg finde tabeller, der refererer til en bestemt række via en fremmednøgle?