Postgres:SQL列出表外键
有没有办法使用SQL来列出给定表的所有外键? 我知道表名/模式,我可以插入。
你可以通过information_schema表来做到这一点。 例如:
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 tc.table_name='mytable';
psql做到这一点,如果你启动psql:
psql -E
它会显示你到底在执行什么查询。 在find外键的情况下,它是:
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
在这种情况下,16485是我正在查看的表的oid – 你可以通过将你的表名转换为regclass来得到这个表:
WHERE r.conrelid = 'mytable'::regclass
模式 – 限定表名称,如果它不是唯一的(或在您的search_path
的第一个):
WHERE r.conrelid = 'myschema.mytable'::regclass
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
对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';
然后:
SELECT * FROM foreign_keys_view WHERE table_name='YourTableNameHere'
;
检查你的解决scheme后,不要忘记标记这一点,当你罚款这有益的
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 c ON c.oid = o.conrelid 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');
此查询也适用于复合键:
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
我认为你在找什么和非常接近@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';
这将列出使用您指定的表作为外键的所有表
您可以使用PostgreSQL系统目录 。 也许你可以查询pg_constraint来请求外键。 您也可以使用信息模式
在PostgreSQL提示符下发出\d+ tablename
,除了显示表列的数据types外,它还会显示索引和外键。
对不起,没有注意到这条消息已被修剪。
为了扩展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%'
使用密钥所引用的主键的名称并查询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')
这里'TABLE_NAME_pkey'是外键引用的主键的名字。
这是来自PostgreSQL邮件列表的Andreas Joseph Krogh的解决scheme: 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;
这个解决scheme处理引用多个列的外键,并避免重复(其他一些答案无法执行)。 我唯一改变的是variables名称。
以下是一个返回引用permission
表的所有employee
列的示例:
SELECT source_column FROM foreign_keys WHERE source_table = 'employee'::regclass AND target_table = 'permission'::regclass;
现有的答案没有给我的结果,我真正想要他们的forms。所以这里是我的(庞大)查询有关外键的信息。
一些注意事项:
- 用于生成
from_cols
和to_cols
可以在Postgres 9.4和更高版本中使用WITH ORDINALITY
而不是使用窗口函数的hackery来简化。 - 这些相同的expression式依赖查询规划器不改变
UNNEST
返回的结果UNNEST
。 我不认为它会,但我没有任何多列外键在我的数据集进行testing。 添加9.4细节完全消除了这种可能性。 - 查询本身需要Postgres 9.0或更高版本(8.x在集合函数中不允许
ORDER BY
) - 如果您需要一个列数组而不是逗号分隔的string,请将
STRING_AGG
replace为STRING_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;
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
我写了一个喜欢和经常使用的解决scheme。 该代码位于http://code.google.com/p/pgutils/ 。 请参阅pgutils.foreign_keys视图。
不幸的是,这里的输出太罗嗦了。 但是,您可以在此处尝试使用公共版本的数据库,如下所示:
$ psql -h unison-db.org -U PUBLIC -d unison -c 'select * from pgutils.foreign_keys;
这至less与8.3一起工作。 如果需要,我预计在未来几个月内会更新它。
-Reece
我创build了一个小工具来查询,然后比较数据库模式:将PostgreSQL数据库模式转储到文本
有关于FK的信息,但ollyc响应给出了更多的细节。
注意:在阅读约束列时,不要忘记列的顺序!
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)