Postgres: SQL, aby wyświetlić klucze obce tabeli

219

Czy istnieje sposób używania SQL do wyświetlania listy wszystkich kluczy obcych dla danej tabeli? Znam nazwę / schemat tabeli i mogę to podłączyć.

smack0007
źródło
Proponuję użyć odpowiedzi @Magnus . Najprostszy, najczystszy, najszybszy.
Erwin Brandstetter,

Odpowiedzi:

373

Możesz to zrobić za pomocą tabel Information_schema. Na przykład:

SELECT
    tc.table_schema, 
    tc.constraint_name, 
    tc.table_name, 
    kcu.column_name, 
    ccu.table_schema AS foreign_table_schema,
    ccu.table_name AS foreign_table_name,
    ccu.column_name AS foreign_column_name 
FROM 
    information_schema.table_constraints AS tc 
    JOIN information_schema.key_column_usage AS kcu
      ON tc.constraint_name = kcu.constraint_name
      AND tc.table_schema = kcu.table_schema
    JOIN information_schema.constraint_column_usage AS ccu
      ON ccu.constraint_name = tc.constraint_name
      AND ccu.table_schema = tc.table_schema
WHERE tc.constraint_type = 'FOREIGN KEY' AND tc.table_name='mytable';
ollyc
źródło
8
nazwa_tabeli = 'mytable' powinna być tc.table_name = 'mytable', w przeciwnym razie generuje niejednoznaczny błąd
interrepion
15
+1, bardzo pomocne. Aby kwerenda była bardziej niezawodna, prawdopodobnie powinna również dołączyć do schematu constraint_schema, ponieważ możliwe jest, że dwa schematy będą miały ograniczenia o tej samej nazwie. Coś w stylu: FROM information_schema.table_constraints AS tc JOIN information_schema.key_column_usage AS kcu USING (constraint_schema, constraint_name) JOIN information_schema.constraint_column_usage AS ccu USING (constraint_schema, constraint_name)
EMP
8
To się psuje, gdy w ograniczeniu jest kilka kolumn, prawda? Wydaje się, że nie ma właściwego sposobu na powiązanie kolumn pk z kolumnami fk za pomocą BT_ informacji.
fionbio
5
Rzeczywiście zrywa z więcej niż jedną kolumną w ograniczeniu. W przypadku Postgres istnieje sposób na uzyskanie tych informacji ze schematu pg_catalog. Zobacz moją odpowiedź poniżej.
martin
9
Zapytanie jest nieprawidłowe. Zakłada, że ​​nazwy ograniczeń nie mogą się powtarzać, co jest fałszem. Ograniczenia o tej samej nazwie mogą istnieć w różnych przestrzeniach nazw. Używasz constraint_name, aby dołączyć. Dołączanie zarówno do nazwy ograniczenia, jak i nazwy schematu nie będzie działać, ponieważ nie jesteś pewien, czy oba ograniczenia są takie same. Jedyną opcją jest użycie pg_constraints, pg_class itp. Przy użyciu oids do przyłączenia. Katalog ANSI Postgres jest tylko dla zgodności, ale jest wadliwy. pg_catalog to droga. Prawidłowa odpowiedź znajduje się tutaj dba.stackexchange.com/questions/36979/retrieving-all-pk-and-fk
Tulains Córdova
69

psql to robi, a jeśli uruchomisz psql:

psql -E

pokaże dokładnie, jakie zapytanie jest wykonywane. W przypadku znalezienia kluczy obcych jest to:

SELECT conname,
  pg_catalog.pg_get_constraintdef(r.oid, true) as condef
FROM pg_catalog.pg_constraint r
WHERE r.conrelid = '16485' AND r.contype = 'f' ORDER BY 1

W tym przypadku 16485 jest oid stołu, na który patrzę - możesz go zdobyć, po prostu rzucając tablename, aby zmienić klasę:

WHERE r.conrelid = 'mytable'::regclass

Schemat kwalifikuj nazwę tabeli, jeśli nie jest unikalna (lub pierwsza w twoim search_path):

WHERE r.conrelid = 'myschema.mytable'::regclass
Magnus Hagander
źródło
2
To bardzo przydatne! Postgres wydaje się mieć milion takich funkcji, które upraszczają wszystko. Teraz jak je zapamiętać?
epic_fil
5
@Phil: Potrzebujesz tylko ogólnego pomysłu. Niech instrukcja zapamięta resztę.
Erwin Brandstetter,
3
aby wyświetlić listę wszystkich kluczy obcych kierowanych do tabeli:SELECT conname, pg_catalog.pg_get_constraintdef(r.oid, true) as condef FROM pg_catalog.pg_constraint r WHERE r.confrelid = 'myschema.mytable'::regclass;
regilero,
1
@ErwinBrandstetter jak zrobić, aby uzyskać nazwę zagranicznego stołu?
Wellington Silva Ribeiro,
2
Nie rozumiem, jakiego polecenia należy użyć? psql -E -U username -d database ThenWHAT?
Poutrathor
49

Problem \d+ tablenamez pytaniem PostgreSQL, oprócz pokazywania typów danych kolumny tabeli, pokazuje indeksy i klucze obce.

Gre Hahn
źródło
Niestety nie zauważyłem, że mój komentarz został przycięty. Jeśli przynajmniej możesz spróbować, zobaczysz również odwzorowania kluczy obcych.
Gre Hahn
45

Odpowiedź Ollyca jest dobra, ponieważ nie jest specyficzna dla Postgresa, ale ulega awarii, gdy klucz obcy odnosi się do więcej niż jednej kolumny. Poniższe zapytanie działa dla dowolnej liczby kolumn, ale w dużej mierze opiera się na rozszerzeniach Postgres:

select 
    att2.attname as "child_column", 
    cl.relname as "parent_table", 
    att.attname as "parent_column",
    conname
from
   (select 
        unnest(con1.conkey) as "parent", 
        unnest(con1.confkey) as "child", 
        con1.confrelid, 
        con1.conrelid,
        con1.conname
    from 
        pg_class cl
        join pg_namespace ns on cl.relnamespace = ns.oid
        join pg_constraint con1 on con1.conrelid = cl.oid
    where
        cl.relname = 'child_table'
        and ns.nspname = 'child_schema'
        and con1.contype = 'f'
   ) con
   join pg_attribute att on
       att.attrelid = con.confrelid and att.attnum = con.child
   join pg_class cl on
       cl.oid = con.confrelid
   join pg_attribute att2 on
       att2.attrelid = con.conrelid and att2.attnum = con.parent
jaskółka oknówka
źródło
przed 8.4 najpierw należy utworzyć funkcję unnest. wiki.postgresql.org/wiki/Array_Unnest
maletin
Gdzie wstawia nazwę tabeli do tego zapytania? Wprowadzone dosłownie powyższe zwraca 0 wierszy na moim PSQL DB, który ma dziesiątki kluczy obcych.
Phrogz,
4
Zastępujesz „child_table” i „child_schema” nazwami tabeli i jej schematu
martin
to nie mówi ci nazwy fkey.
Evan Carroll
@EvanCarroll Zaktualizowałem moją odpowiedź, aby zawierała nazwę klucza.
martin
31

Rozszerzenie przepisu ollyc:

CREATE VIEW foreign_keys_view AS
SELECT
    tc.table_name, kcu.column_name,
    ccu.table_name AS foreign_table_name,
    ccu.column_name AS foreign_column_name
FROM
    information_schema.table_constraints AS tc
    JOIN information_schema.key_column_usage 
        AS kcu ON tc.constraint_name = kcu.constraint_name
    JOIN information_schema.constraint_column_usage 
        AS ccu ON ccu.constraint_name = tc.constraint_name
WHERE constraint_type = 'FOREIGN KEY';

Następnie:

SELECT * FROM foreign_keys_view WHERE table_name='YourTableNameHere';

Mvoicem
źródło
Dzięki, idealny do ponownego użycia.
schellingerht
16

sprawdź post ff dla swojego rozwiązania i nie zapomnij zaznaczyć tego, gdy okaże się to pomocne

http://errorbank.blogspot.com/2011/03/list-all-foreign-keys-references-for.html

SELECT
  o.conname AS constraint_name,
  (SELECT nspname FROM pg_namespace WHERE oid=m.relnamespace) AS source_schema,
  m.relname AS source_table,
  (SELECT a.attname FROM pg_attribute a WHERE a.attrelid = m.oid AND a.attnum = o.conkey[1] AND a.attisdropped = false) AS source_column,
  (SELECT nspname FROM pg_namespace WHERE oid=f.relnamespace) AS target_schema,
  f.relname AS target_table,
  (SELECT a.attname FROM pg_attribute a WHERE a.attrelid = f.oid AND a.attnum = o.confkey[1] AND a.attisdropped = false) AS target_column
FROM
  pg_constraint o LEFT JOIN pg_class f ON f.oid = o.confrelid LEFT JOIN pg_class m ON m.oid = o.conrelid
WHERE
  o.contype = 'f' AND o.conrelid IN (SELECT oid FROM pg_class c WHERE c.relkind = 'r');
Sheldon
źródło
Oferuje dwa SQL-y, które działają na PostgreSQL 9.1 (po poprawieniu nieprawidłowego znaku ucieczki umieść w SQL swoją „tablename” (bez prefiksu schematu)).
alfonx
2
+1: jest to jedyne rozwiązanie, które nie zwraca duplikatów.
Olivier MATROT
do tego rozwiązania działa dobrze i nie zwraca duplikatów.
Fuhrmann
1
To rozwiązanie pokaże tylko pierwszą kolumnę dowolnego wielokolumnowego klucza obcego ... ale wygląda o wiele prostiej niż ten, który właśnie zamieściłem, który będzie wielokrotnością.
dewin 22.04.16
12

To zapytanie działa poprawnie również z kluczami złożonymi:

select c.constraint_name
    , x.table_schema as schema_name
    , x.table_name
    , x.column_name
    , y.table_schema as foreign_schema_name
    , y.table_name as foreign_table_name
    , y.column_name as foreign_column_name
from information_schema.referential_constraints c
join information_schema.key_column_usage x
    on x.constraint_name = c.constraint_name
join information_schema.key_column_usage y
    on y.ordinal_position = x.position_in_unique_constraint
    and y.constraint_name = c.unique_constraint_name
order by c.constraint_name, x.ordinal_position
oscavi
źródło
2
Dołączasz do kolumn w nazwie „constraint_name”, więc zadziała to tylko wtedy, gdy wszystkie nazwy wiązań będą unikalne (we wszystkich tabelach we wszystkich schematach). Zwykle nie jest to wymóg, a zatem nie jest egzekwowany przez bazę danych.
Zilk,
3
Dzięki. To jedyna odpowiedź, która pokazuje, jak używać schematu_informacji, aby poprawnie obsługiwać wiele kolumn.
Samuel Danielson
To rozwiązanie działa. Nie tworzy duplikatów i obsługuje wiele pól w FK.
Igor
9

Myślę, że to, czego szukałeś i bardzo blisko tego, co napisał @ollyc, to:

SELECT
tc.constraint_name, tc.table_name, kcu.column_name, 
ccu.table_name AS foreign_table_name,
ccu.column_name AS foreign_column_name 
FROM 
information_schema.table_constraints AS tc 
JOIN information_schema.key_column_usage AS kcu
  ON tc.constraint_name = kcu.constraint_name
JOIN information_schema.constraint_column_usage AS ccu
  ON ccu.constraint_name = tc.constraint_name
WHERE constraint_type = 'FOREIGN KEY' AND ccu.table_name='YourTableNameHere';

Spowoduje to wyświetlenie listy wszystkich tabel, które używają określonej tabeli jako klucza obcego

Shaun McCready
źródło
9

krótki, ale słodki głos, jeśli to działa.

select  * from information_schema.key_column_usage where constraint_catalog=current_catalog and table_name='your_table_name' and position_in_unique_constraint notnull;
NikhilP
źródło
Zadziałało, pisząc z PG 12.2
Jack Kinsella
5

Żadna z istniejących odpowiedzi nie dała mi wyników w takiej formie, w jakiej naprawdę ich chciałem. Oto moje (gigantyczne) zapytanie o znalezienie informacji o obcych kluczach.

Kilka uwag:

  • Wyrażenia używane do generowania from_colsi to_colsmożna je znacznie uprościć w Postgresie 9.4 i nowszych przy WITH ORDINALITYużyciu hakerów zamiast funkcji okna, których używam.
  • Te same wyrażenia opierają się na narzędziu do planowania zapytań, które nie zmienia zwracanej kolejności wyników UNNEST. Nie sądzę, że tak będzie, ale w zestawie danych nie mam żadnych kluczy obcych z wieloma kolumnami. Dodanie 9,4 subtelności całkowicie eliminuje tę możliwość.
  • Samo zapytanie wymaga Postgres 9.0 lub nowszego (8.x nie zezwalał ORDER BYna funkcje agregujące)
  • Wymień STRING_AGGsię ARRAY_AGGjeśli chcesz tablicę kolumn zamiast ciąg oddzielonych przecinkami.

-

SELECT
    c.conname AS constraint_name,
    (SELECT n.nspname FROM pg_namespace AS n WHERE n.oid=c.connamespace) AS constraint_schema,

    tf.name AS from_table,
    (
        SELECT STRING_AGG(QUOTE_IDENT(a.attname), ', ' ORDER BY t.seq)
        FROM
            (
                SELECT
                    ROW_NUMBER() OVER (ROWS UNBOUNDED PRECEDING) AS seq,
                    attnum
                FROM
                    UNNEST(c.conkey) AS t(attnum)
            ) AS t
            INNER JOIN pg_attribute AS a ON a.attrelid=c.conrelid AND a.attnum=t.attnum
    ) AS from_cols,

    tt.name AS to_table,
    (
        SELECT STRING_AGG(QUOTE_IDENT(a.attname), ', ' ORDER BY t.seq)
        FROM
            (
                SELECT
                    ROW_NUMBER() OVER (ROWS UNBOUNDED PRECEDING) AS seq,
                    attnum
                FROM
                    UNNEST(c.confkey) AS t(attnum)
            ) AS t
            INNER JOIN pg_attribute AS a ON a.attrelid=c.confrelid AND a.attnum=t.attnum
    ) AS to_cols,

    CASE confupdtype WHEN 'r' THEN 'restrict' WHEN 'c' THEN 'cascade' WHEN 'n' THEN 'set null' WHEN 'd' THEN 'set default' WHEN 'a' THEN 'no action' ELSE NULL END AS on_update,
    CASE confdeltype WHEN 'r' THEN 'restrict' WHEN 'c' THEN 'cascade' WHEN 'n' THEN 'set null' WHEN 'd' THEN 'set default' WHEN 'a' THEN 'no action' ELSE NULL END AS on_delete,
    CASE confmatchtype::text WHEN 'f' THEN 'full' WHEN 'p' THEN 'partial' WHEN 'u' THEN 'simple' WHEN 's' THEN 'simple' ELSE NULL END AS match_type,  -- In earlier postgres docs, simple was 'u'nspecified, but current versions use 's'imple.  text cast is required.

    pg_catalog.pg_get_constraintdef(c.oid, true) as condef
FROM
    pg_catalog.pg_constraint AS c
    INNER JOIN (
        SELECT pg_class.oid, QUOTE_IDENT(pg_namespace.nspname) || '.' || QUOTE_IDENT(pg_class.relname) AS name
        FROM pg_class INNER JOIN pg_namespace ON pg_class.relnamespace=pg_namespace.oid
    ) AS tf ON tf.oid=c.conrelid
    INNER JOIN (
        SELECT pg_class.oid, QUOTE_IDENT(pg_namespace.nspname) || '.' || QUOTE_IDENT(pg_class.relname) AS name
        FROM pg_class INNER JOIN pg_namespace ON pg_class.relnamespace=pg_namespace.oid
    ) AS tt ON tt.oid=c.confrelid
WHERE c.contype = 'f' ORDER BY 1;
dewin
źródło
5

Jeszcze jeden sposób:

WITH foreign_keys AS (
    SELECT
      conname,
      conrelid,
      confrelid,
      unnest(conkey)  AS conkey,
      unnest(confkey) AS confkey
    FROM pg_constraint
    WHERE contype = 'f' -- AND confrelid::regclass = 'your_table'::regclass
)
-- if confrelid, conname pair shows up more than once then it is multicolumn foreign key
SELECT fk.conname as constraint_name,
       fk.confrelid::regclass as referenced_table, af.attname as pkcol,
       fk.conrelid::regclass as referencing_table, a.attname as fkcol
FROM foreign_keys fk
JOIN pg_attribute af ON af.attnum = fk.confkey AND af.attrelid = fk.confrelid
JOIN pg_attribute a ON a.attnum = conkey AND a.attrelid = fk.conrelid
ORDER BY fk.confrelid, fk.conname
;
Konrad Perzyna
źródło
4

Użyj nazwy klucza głównego, do którego odwołują się klucze, i prześlij zapytanie do schematu informacyjnego:

select table_name, column_name
from information_schema.key_column_usage
where constraint_name IN (select constraint_name
  from information_schema.referential_constraints 
  where unique_constraint_name = 'TABLE_NAME_pkey')

Tutaj „TABLE_NAME_pkey” to nazwa klucza podstawowego, do którego odwołują się klucze obce.

markmnl
źródło
4

Oto rozwiązanie Andreasa Josepha Krogha z listy mailingowej PostgreSQL: http://www.postgresql.org/message-id/[email protected]

SELECT source_table::regclass, source_attr.attname AS source_column,
    target_table::regclass, target_attr.attname AS target_column
FROM pg_attribute target_attr, pg_attribute source_attr,
  (SELECT source_table, target_table, source_constraints[i] source_constraints, target_constraints[i] AS target_constraints
   FROM
     (SELECT conrelid as source_table, confrelid AS target_table, conkey AS source_constraints, confkey AS target_constraints,
       generate_series(1, array_upper(conkey, 1)) AS i
      FROM pg_constraint
      WHERE contype = 'f'
     ) query1
  ) query2
WHERE target_attr.attnum = target_constraints AND target_attr.attrelid = target_table AND
      source_attr.attnum = source_constraints AND source_attr.attrelid = source_table;

To rozwiązanie obsługuje klucze obce, które odwołują się do wielu kolumn, i pozwala uniknąć duplikatów (czego niektóre inne odpowiedzi nie robią). Jedyne, co zmieniłem, to nazwy zmiennych.

Oto przykład, który zwraca wszystkie employeekolumny, które odwołują się do permissiontabeli:

SELECT source_column
FROM foreign_keys
WHERE source_table = 'employee'::regclass AND target_table = 'permission'::regclass;
Gili
źródło
4

Aby rozwinąć doskonałą odpowiedź Martina tutaj, jest zapytanie, które pozwala filtrować na podstawie tabeli nadrzędnej i pokazuje nazwę tabeli podrzędnej z każdą tabelą nadrzędną, dzięki czemu można zobaczyć wszystkie zależne tabele / kolumny na podstawie ograniczeń klucza obcego w stół nadrzędny.

select 
    con.constraint_name,
    att2.attname as "child_column", 
    cl.relname as "parent_table", 
    att.attname as "parent_column",
    con.child_table,
    con.child_schema
from
   (select 
        unnest(con1.conkey) as "parent", 
        unnest(con1.confkey) as "child", 
        con1.conname as constraint_name,
        con1.confrelid, 
        con1.conrelid,
        cl.relname as child_table,
        ns.nspname as child_schema
    from 
        pg_class cl
        join pg_namespace ns on cl.relnamespace = ns.oid
        join pg_constraint con1 on con1.conrelid = cl.oid
    where  con1.contype = 'f'
   ) con
   join pg_attribute att on
       att.attrelid = con.confrelid and att.attnum = con.child
   join pg_class cl on
       cl.oid = con.confrelid
   join pg_attribute att2 on
       att2.attrelid = con.conrelid and att2.attnum = con.parent
   where cl.relname like '%parent_table%'       
Cervo
źródło
1
Zapytanie w zaakceptowanej odpowiedzi dodaje 1,2 sekundy do zapytania ~ 0,03, twoje dodaje tylko 0,01, dzięki!
AVProgrammer,
3

Właściwe rozwiązanie problemu, używanie information_schema, praca z kluczami wielokolumnowymi, prawidłowe łączenie kolumn o różnych nazwach w obu tabelach, a także kompatybilność z ms sqlsever:

select fks.TABLE_NAME as foreign_key_table_name
, fks.CONSTRAINT_NAME as foreign_key_constraint_name
, kcu_foreign.COLUMN_NAME as foreign_key_column_name
, rc.UNIQUE_CONSTRAINT_NAME as primary_key_constraint_name
, pks.TABLE_NAME as primary_key_table_name
, kcu_primary.COLUMN_NAME as primary_key_column_name
from INFORMATION_SCHEMA.TABLE_CONSTRAINTS fks -- foreign keys
inner join INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu_foreign -- the columns of the above keys
    on fks.TABLE_CATALOG = kcu_foreign.TABLE_CATALOG
    and fks.TABLE_SCHEMA = kcu_foreign.TABLE_SCHEMA
    and fks.TABLE_NAME = kcu_foreign.TABLE_NAME
    and fks.CONSTRAINT_NAME = kcu_foreign.CONSTRAINT_NAME
inner join INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc -- referenced constraints
    on rc.CONSTRAINT_CATALOG = fks.CONSTRAINT_CATALOG
    and rc.CONSTRAINT_SCHEMA = fks.CONSTRAINT_SCHEMA
    and rc.CONSTRAINT_NAME = fks.CONSTRAINT_NAME
inner join INFORMATION_SCHEMA.TABLE_CONSTRAINTS pks -- primary keys (referenced by fks)
    on rc.UNIQUE_CONSTRAINT_CATALOG = pks.CONSTRAINT_CATALOG
    and rc.UNIQUE_CONSTRAINT_SCHEMA = pks.CONSTRAINT_SCHEMA
    and rc.UNIQUE_CONSTRAINT_NAME = pks.CONSTRAINT_NAME
inner join INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu_primary
    on pks.TABLE_CATALOG = kcu_primary.TABLE_CATALOG
    and pks.TABLE_SCHEMA = kcu_primary.TABLE_SCHEMA
    and pks.TABLE_NAME = kcu_primary.TABLE_NAME
    and pks.CONSTRAINT_NAME = kcu_primary.CONSTRAINT_NAME
    and kcu_foreign.ORDINAL_POSITION = kcu_primary.ORDINAL_POSITION -- this joins the columns
where fks.TABLE_SCHEMA = 'dbo' -- replace with schema name
and fks.TABLE_NAME = 'your_table_name' -- replace with table name
and fks.CONSTRAINT_TYPE = 'FOREIGN KEY'
and pks.CONSTRAINT_TYPE = 'PRIMARY KEY'
order by fks.constraint_name, kcu_foreign.ORDINAL_POSITION

Uwaga: Istnieją pewne różnice między implementacjami potgresql i sqlserver, z information_schemaktórych pierwsza odpowiedź daje różne wyniki w dwóch systemach - jedna pokazuje nazwy kolumn dla tabeli kluczy obcych, a druga dla tabeli kluczy podstawowych. Z tego powodu postanowiłem użyć zamiast tego widoku KEY_COLUMN_USAGE.

jakubiszon
źródło
Schemat informacyjny wydaje się być właściwą odpowiedzią, ale tak naprawdę chcesz tabel pg_catalog: pg_constraint itp. Bardzo nas to ugryzło. jeśli twoja baza danych ma wiele ograniczeń, mogą wystąpić problemy z wydajnością ...
hajikelist
Powyższy warunek ORDINAL_POSITIONmoże dawać niepoprawny wynik, gdy kolejność kolumn w kluczu obcym różni się od kolejności kolumn w ograniczeniu unikalnym. Wierzę, że nie powinno być połączone na kcu_foreign.POSITION_IN_UNIQUE_CONSTRAINT = kcu_primary.ORDINAL_POSITION aktualizacji : Również, klucz obcy może zależeć od ograniczeń UNIQUE, tak więc myślę, że należy usunąć pks.CONSTRAINT_TYPEwarunek i można po prostu dołączyć rcdo kcu_primarybezpośrednio
EASD
Podobną odpowiedź zrobiłem tutaj: stackoverflow.com/a/62260908/9093051
easd
2
SELECT r.conname
      ,ct.table_name
      ,pg_catalog.pg_get_constraintdef(r.oid, true) as condef
  FROM pg_catalog.pg_constraint r, information_schema.constraint_table_usage ct
 WHERE r.contype = 'f' 
   AND r.conname = ct.constraint_name
 ORDER BY 1
Pugazendhi Asaimuthu
źródło
2

Napisałem rozwiązanie, które często lubi i używa. Kod znajduje się na stronie http://code.google.com/p/pgutils/ . Zobacz widok pgutils.foreign_keys.

Niestety, wynik jest zbyt trudny, aby go tutaj uwzględnić. Możesz jednak wypróbować go w publicznej wersji bazy danych tutaj:

$ psql -h unison-db.org -U PUBLIC -d unison -c 'select * from pgutils.foreign_keys;

Działa to przynajmniej z 8.3. Przewiduję aktualizację w razie potrzeby w ciągu najbliższych kilku miesięcy.

-Reece

Reece
źródło
1
Link do projektu jest teraz martwy.
pimlottc
@pimlottc: Przeniesiono na bitbucket.org/reece/pgutils . Dzięki za zwrócenie na to uwagi.
Reece
1

Stworzyłem małe narzędzie do wyszukiwania, a następnie porównywania schematu bazy danych: Zrzuć schemat DB PostgreSQL na tekst

Są informacje o FK, ale odpowiedź ollyc podaje więcej szczegółów.

Michał Niklas
źródło
0

Uwaga: Nie zapomnij o kolejności kolumn podczas czytania kolumn z ograniczeniami!

SELECT conname, attname
  FROM pg_catalog.pg_constraint c 
  JOIN pg_catalog.pg_attribute a ON a.attrelid = c.conrelid AND a.attnum = ANY (c.conkey)
 WHERE attrelid = 'schema.table_name'::regclass
 ORDER BY conname, array_position(c.conkey, a.attnum)
Nashev
źródło
0

To jest to, czego aktualnie używam, wyświetli tabelę i jej ograniczenia Fkey [usuń klauzulę tabeli i wyświetli wszystkie tabele w bieżącym katalogu]:

SELECT

    current_schema() AS "schema",
    current_catalog AS "database",
    "pg_constraint".conrelid::regclass::text AS "primary_table_name",
    "pg_constraint".confrelid::regclass::text AS "foreign_table_name",

    (
        string_to_array(
            (
                string_to_array(
                    pg_get_constraintdef("pg_constraint".oid),
                    '('
                )
            )[2],
            ')'
        )
    )[1] AS "foreign_column_name",

    "pg_constraint".conindid::regclass::text AS "constraint_name",

    TRIM((
        string_to_array(
            pg_get_constraintdef("pg_constraint".oid),
            '('
        )
    )[1]) AS "constraint_type",

    pg_get_constraintdef("pg_constraint".oid) AS "constraint_definition"

FROM pg_constraint AS "pg_constraint"

JOIN pg_namespace AS "pg_namespace" ON "pg_namespace".oid = "pg_constraint".connamespace

WHERE
    --fkey and pkey constraints
    "pg_constraint".contype IN ( 'f', 'p' )
    AND
    "pg_namespace".nspname = current_schema()
    AND
    "pg_constraint".conrelid::regclass::text IN ('whatever_table_name')
lista pielęgniarek
źródło
0

najszybszy do zweryfikowania bezpośrednio w odpowiedzi bash oparty w całości na tej odpowiedzi

IFS='' read -r -d '' sql_code << EOF_SQL_CODE
      SELECT
      o.oid
      , o.conname AS constraint_name
      , (SELECT nspname FROM pg_namespace WHERE oid=m.relnamespace) AS source_schema
      , m.relname AS source_table
      , (SELECT a.attname FROM pg_attribute a
      WHERE a.attrelid = m.oid AND a.attnum = o.conkey[1] AND a.attisdropped = false) AS source_column
      , (SELECT nspname FROM pg_namespace
      WHERE oid=f.relnamespace) AS target_schema
      , f.relname AS target_table
      , (SELECT a.attname FROM pg_attribute a
      WHERE a.attrelid = f.oid AND a.attnum = o.confkey[1] AND a.attisdropped = false) AS target_column
      , ROW_NUMBER () OVER (ORDER BY o.oid) as rowid
      FROM pg_constraint o
      LEFT JOIN pg_class f ON f.oid = o.confrelid
      LEFT JOIN pg_class m ON m.oid = o.conrelid
      WHERE 1=1
      AND o.contype = 'f'
      AND o.conrelid IN (SELECT oid FROM pg_class c WHERE c.relkind = 'r')
EOF_SQL_CODE

psql -d my_db -c "$sql_code"
Yordan Georgiev
źródło