Testa installationen
Du antar begränsningsnamnet test_def_abc_id_fkey
, standardnamnet som härrör från din installation i Postgres 11 eller äldre. Värt att notera är dock att standardnamnen har förbättrats för Postgres 12, där samma inställning resulterar i test_def_abc_id_abc_id2_fkey
. Versionsinformationen för Postgres 12:
Se:
db<>fiol här
Så låt oss använda det explicita namnet test_def_abc_fkey
för FK-begränsningen för att undvika förvirring:
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)
);
Och att fungerar i Postgres 9.5 - Postgres 12.
Även i Postgres 9.3.
(Jag hade ett felaktigt intryck av en faktisk begränsning skulle krävas.)
Svar
Din observation från att fråga informationsschemat gäller:
SELECT *
FROM information_schema.referential_constraints
WHERE constraint_name = 'test_def_abc_fkey'; -- unequivocal name
Vi får en rad, men de tre fälten unique_constraint_catalog
, unique_constraint_schema
och unique_constraint_name
är NULL
.
Förklaringen verkar enkel. Dessa kolumner beskriver, som manualen uttrycker det:
Men det finns ingen UNIQUE begränsning
, bara en UNIQUE
index
. En UNIQUE
begränsning implementeras med en UNIQUE
index i Postgres. Restriktioner definieras av SQL-standarden, index är implementeringsdetaljer. Det finns skillnader som den du upptäckte. Relaterat:
Samma test med en faktisk UNIQUE
begränsning visar data som förväntat:
db<>fiol här
Så det här verkar vara vettigt. Speciellt eftersom informationsschemat definieras också av SQL-standardkommittén och index är inte standardiserade, bara begränsningar. (Ingen indexinformation i informationsschemavyer.)
Allt klart? Inte riktigt.
Men
Det finns en annan informationsschemavy key_column_usage
. Dess sista kolumn beskrivs som:
Fet betoning min. Här, ordningspositionen för kolumnen i index finns i alla fall:
SELECT *
FROM information_schema.key_column_usage
WHERE constraint_name = 'test_def_abc_fkey';
Se:
db<>fiol här
Verkar inkonsekvent.
Vad värre är, handboken
hävdar att en faktisk PRIMÄRNYCKEL
eller UNIQUE
begränsning skulle krävas för att skapa en FREIGN KEY
begränsning:
Verkar vara ett dokumentationsfel ? Om ingen kan peka ut var jag gör fel här, skickar jag en felrapport.
Relaterat:
Lösning
I Postgres är systemkatalogen den faktiska källan till sanningen. Se:
Så du kan använda något sånt här (som jag också la till i fiol ovan):
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';
Returnerar:
conname | fk_table | fk_columns | ref_table | ref_key_columns :---------------- | :------- | :--------------- | :-------- | :-------------- test_def_abc_fkey | test_def | {abc_id,abc_id2} | test_abc | {id,id2}
Relaterat:
- Hitta det refererade tabellnamnet med hjälp av tabell-, fält- och schemanamn
- Hitta refererat fält( s) av främmande nyckelbegränsning
- Hur kan jag hitta tabeller som refererar till en viss rad via en främmande nyckel?