Testopstelling
U neemt de beperkingsnaam test_def_abc_id_fkey
. aan , de standaardnaam die resulteert uit uw instellingen in Postgres 11 of ouder. Het is echter vermeldenswaard dat de standaardnamen zijn verbeterd voor Postgres 12, waar dezelfde instelling resulteert in test_def_abc_id_abc_id2_fkey
. De release-opmerkingen voor Postgres 12:
Zie:
db<>fiddle hier
Laten we dus de expliciete naam test_def_abc_fkey
gebruiken voor de FK-beperking om verwarring te voorkomen:
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)
);
En dat werkt in Postgres 9.5 - Postgres 12.
Zelfs in Postgres 9.3.
(Ik had een verkeerde indruk gekregen van een daadwerkelijke beperking zou vereist zijn.)
Antwoord
Uw observatie van het opvragen van het informatieschema houdt in:
SELECT *
FROM information_schema.referential_constraints
WHERE constraint_name = 'test_def_abc_fkey'; -- unequivocal name
We krijgen een rij, maar de drie velden unique_constraint_catalog
, unique_constraint_schema
en unique_constraint_name
zijn NULL
.
De verklaring lijkt simpel. Die kolommen beschrijven, zoals de handleiding het stelt:
Maar er is geen UNIQUE
beperking
, gewoon een UNIQUE
index
. Een UNIQUE
beperking wordt geïmplementeerd met behulp van een UNIQUE
index in Postgres. Beperkingen worden gedefinieerd door de SQL-standaard, indexen zijn implementatiedetails. Er zijn verschillen zoals degene die je hebt ontdekt. Gerelateerd:
Dezelfde test met een echte UNIQUE
beperking toont gegevens zoals verwacht:
db<>fiddle hier
Dit lijkt dus logisch. Vooral omdat het informatieschema wordt ook gedefinieerd door de SQL-standaardcommissie en indexen zijn niet gestandaardiseerd, alleen beperkingen. (Geen indexinformatie in informatieschemaweergaven.)
Alles duidelijk? Niet helemaal.
Echter
Er is nog een informatieschemaweergave key_column_usage
. De laatste kolom wordt beschreven als:
Vet nadruk de mijne. Hier de ordinale positie van de kolom in de index wordt toch vermeld:
SELECT *
FROM information_schema.key_column_usage
WHERE constraint_name = 'test_def_abc_fkey';
Zie:
db<>fiddle hier
Lijkt onsamenhangend.
Wat erger is, de handleiding
beweert dat een werkelijke PRIMARY KEY
of UNIQUE
beperking zou vereist zijn voor het maken van een FOREIGN KEY
beperking:
Lijkt een documentatiefout te zijn ? Als niemand kan aangeven waar ik hier de fout in ga, zal ik een bugrapport indienen.
Gerelateerd:
Oplossing
In Postgres is de systeemcatalogus de eigenlijke bron van waarheid. Zie:
Dus je zou zoiets kunnen gebruiken (zoals ik ook heb toegevoegd in de viool hierboven):
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';
Retourneren:
conname | fk_table | fk_columns | ref_table | ref_key_columns :---------------- | :------- | :--------------- | :-------- | :-------------- test_def_abc_fkey | test_def | {abc_id,abc_id2} | test_abc | {id,id2}
Gerelateerd:
- Zoek de tabelnaam waarnaar wordt verwezen met de tabel-, veld- en schemanaam
- Field waarnaar wordt verwezen( s) van externe sleutelbeperking
- Hoe kan ik tabellen vinden die via een externe sleutel naar een bepaalde rij verwijzen?