Postgres:SQL列出表外键

sma*_*007 192 sql postgresql

有没有办法使用SQL列出给定表的所有外键?我知道表名/模式,我可以将其插入.

oll*_*lyc 332

您可以通过information_schema表执行此操作.例如:

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';
Run Code Online (Sandbox Code Playgroud)

  • +1,非常有帮助.为了使查询更加健壮,它也应该加入constraint_schema,因为两个模式可能具有相同名称的约束.类似于:`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)` (14认同)
  • table_name ='mytable'应为tc.table_name ='mytable',否则会引发模糊错误 (8认同)
  • 查询错误.它假定约束名称不能重复,这是错误的.具有相同名称的约束可以存在于不同的命名空间中.您正在使用constraint_name进行连接.同时加入constraint_name和模式名称也不起作用,因为您不确定这两个约束是否相同.唯一的选择是使用oids加入pg_constraints,pg_class等.Postgres的ANSI目录仅用于合规,但它存在缺陷.pg_catalog是要走的路.正确的答案在这里http://dba.stackexchange.com/questions/36979/retrieving-all-pk-and-fk (8认同)
  • 当约束中有多个列时会中断,不是吗?似乎没有使用information_schema BTW将pk列与fk列关联的正确方法. (6认同)
  • 它确实在约束中打破了多个列.对于Postgres,有一种从pg_catalog架构获取此信息的方法.请参阅下面的答案. (3认同)

Mag*_*der 64

psql执行此操作,如果您使用以下命令启动psql:

psql -E
Run Code Online (Sandbox Code Playgroud)

它会准确显示执行的查询.在查找外键的情况下,它是:

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
Run Code Online (Sandbox Code Playgroud)

在这种情况下,16485是我正在查看的表的oid - 你可以通过将你的tablename转换为regclass来获得那个:

WHERE r.conrelid = 'mytable'::regclass
Run Code Online (Sandbox Code Playgroud)

如果表名不是唯一的(或者是你的第一个search_path),则表格限定表名:

WHERE r.conrelid = 'myschema.mytable'::regclass
Run Code Online (Sandbox Code Playgroud)

  • @Phil:你只需要一个大致的想法.[让手册记住其余部分.](http://www.postgresql.org/docs/current/interactive/functions-info.html#CUNCTIONS-INFO-CATALOG-TABLE) (5认同)
  • 列出所有以表为目标的外键:`SELECT conname,pg_catalog.pg_get_constraintdef(r.oid,true)as condef FROM pg_catalog.pg_constraint r WHERE r.confrelid ='myschema.mytable':: regclass;` (3认同)
  • 这非常方便!Postgres似乎有百万个这样的小功能,可以简化所有操作。现在如何记住他们? (2认同)
  • 我不明白,应该使用什么命令?`psql -E -U用户名-d数据库ThenWHAT`? (2认同)

mar*_*tin 43

Ollyc的答案很好,因为它不是Postgres特有的,但是,当外键引用多个列时它会崩溃.以下查询适用于任意数量的列,但它在很大程度上依赖于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
Run Code Online (Sandbox Code Playgroud)

  • 您将'child_table'和'child_schema'替换为表及其架构的名称 (3认同)
  • 我认为 `'child_table'` 实际上是 `'parent_table'`,因为 `cl.relname` 位于 `cl` 表中,该表通过 `confrelid` 连接,该表是被引用的(父)表。如果你想过滤子表,你应该添加 `join pg_class cl2 on cl2.oid = con.conrelid` 然后使用 `cl2.relname = 'child_table'`。 (2认同)

小智 35

问题\d+ tablenamePostgreSQL的提示,除了显示表列的数据类型,它会显示索引和外键.


小智 28

扩展到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';
Run Code Online (Sandbox Code Playgroud)

然后:

SELECT * FROM foreign_keys_view WHERE table_name='YourTableNameHere';


Nik*_*ilP 18

如果它适合你,简短但甜蜜的upvote。

select  * from information_schema.key_column_usage where constraint_catalog=current_catalog and table_name='your_table_name' and position_in_unique_constraint notnull;
Run Code Online (Sandbox Code Playgroud)


小智 13

检查你的解决方案的ff帖子,当你对此有用时不要忘记标记这个

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');
Run Code Online (Sandbox Code Playgroud)

  • +1:这是唯一不返回重复项的解决方案. (2认同)
  • 这个解决方案只会显示任何多列外键的第一列......但看起来比我刚刚发布的可以做倍数的那个简单得多。 (2认同)

小智 12

此查询也适用于复合键:

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
Run Code Online (Sandbox Code Playgroud)

  • 谢谢。这是唯一显示如何使用information_schema正确处理多列的答案。 (3认同)
  • 您正在加入"constraint_name"上的列,因此只有在所有约束名称都是唯一的(跨所有模式的所有表)时才会起作用.这通常不是必需的,因此数据库不强制执行. (2认同)
  • 此解决方案有效。它不会产生重复项,并且可以处理 FK 中的多个字段。 (2认同)

小智 9

我认为你在寻找和@ollyc所写的非常接近的是:

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';
Run Code Online (Sandbox Code Playgroud)

这将列出使用指定表作为外键的所有表


小智 7

另一种方式:

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
;
Run Code Online (Sandbox Code Playgroud)


Gui*_*ido 5

您可以使用PostgreSQL系统目录.也许你可以查询pg_constraint来询问外键.您还可以使用信息架构


mar*_*mnl 5

使用键引用的主键名称并查询 information_schema:

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')
Run Code Online (Sandbox Code Playgroud)

这里“TABLE_NAME_pkey”是外键引用的主键的名称。


Gil*_*ili 5

以下是 Andreas Joseph Krogh 在 PostgreSQL 邮件列表中提出的解决方案: http: //www.postgresql.org/message-id/200811072134.44750.andreak@officenet.no

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;
Run Code Online (Sandbox Code Playgroud)

该解决方案处理引用多个列的外键,并避免重复(其他一些答案无法做到这一点)。我唯一改变的是变量名称。

employee以下是返回引用该表的所有列的示例permission

SELECT source_column
FROM foreign_keys
WHERE source_table = 'employee'::regclass AND target_table = 'permission'::regclass;
Run Code Online (Sandbox Code Playgroud)


Cer*_*rvo 5

为了扩展 Martin 的出色答案,这里有一个查询,它允许您根据父表进行过滤,并显示每个父表的子表的名称,以便您可以根据中的外键约束查看所有依赖表/列父表。

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%'       
Run Code Online (Sandbox Code Playgroud)


dew*_*win 5

现有的答案都没有以我实际想要的形式提供给我结果。这是我的(gargantuan)查询,用于查找有关外键的信息。

一些注意事项:

  • 该表达式用于生成from_colsto_cols可以大大简化对的Postgres 9.4和以后使用WITH ORDINALITY,而不是我使用的是使用窗口功能两轮牛车。
  • 这些相同的表达式依赖于查询计划程序,而不会更改从返回的结果顺序UNNEST。我认为不会,但是我的数据集中没有可用于测试的多列外键。添加9.4个细微之处完全消除了这种可能性。
  • 查询本身需要Postgres 9.0或更高版本(8.x不允许ORDER BY在聚合函数中使用)
  • 如果要使用列而不是逗号分隔的字符串,请替换STRING_AGGARRAY_AGG

--

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;
Run Code Online (Sandbox Code Playgroud)


jak*_*zon 5

问题的正确解决方案,使用information_schema,使用多列键,正确连接两个表中不同名称的列,并与 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
Run Code Online (Sandbox Code Playgroud)

注意:potgresql 和 sqlserver 实现之间存在一些差异,information_schema这使得最佳答案在两个系统上给出不同的结果 - 一个显示外键表的列名,另一个显示主键表的列名。出于这个原因,我决定改用 KEY_COLUMN_USAGE 视图。