Postgres: SQL to list table foreign keys
有没有办法使用SQL列出给定表的所有外键? 我知道表名/模式,我可以将其插入。
您可以通过information_schema表执行此操作。例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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'; |
psql执行此操作,如果您使用以下命令启动psql:
1 | psql -E |
它会准确显示执行的查询。在查找外键的情况下,它是:
1 2 3 4 | 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 - 你可以通过将你的tablename转换为regclass来获得那个:
1 | WHERE r.conrelid = 'mytable'::regclass |
如果表名不是唯一的(或
1 | WHERE r.conrelid = 'myschema.mytable'::regclass |
Ollyc的答案很好,因为它不是Postgres特有的,但是,当外键引用多个列时它会崩溃。以下查询适用于任意数量的列,但它在很大程度上依赖于Postgres扩展:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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 |
在PostgreSQL提示符上发出
扩展到ollyc配方:
1 2 3 4 5 6 7 8 9 10 11 12 | 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'; |
然后:
检查你的解决方案的ff帖子,当你对此有用时,不要忘记标记这个
http://errorbank.blogspot.com/2011/03/list-all-foreign-keys-references-for.html
1 2 3 4 5 6 7 8 9 10 11 12 | 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'); |
此查询也适用于复合键:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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所写的非常接近的是:
1 2 3 4 5 6 7 8 9 10 11 | 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来询问外键。
您还可以使用信息架构
为了扩展Martin的优秀答案,这里有一个查询,它允许您根据父表进行过滤,并显示每个父表的子表的名称,以便您可以根据外键约束查看所有相关表/列。父表。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 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%' |
以下是来自PostgreSQL邮件列表的Andreas Joseph Krogh的解决方案:http://www.postgresql.org/message-id/[email protected]
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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; |
此解决方案处理引用多个列的外键,并避免重复(其他一些答案无法执行)。我唯一改变的是变量名。
下面是一个示例,它返回引用
1 2 3 | SELECT source_column FROM foreign_keys WHERE source_table = 'employee'::regclass AND target_table = 'permission'::regclass; |
现有的答案都没有给出我实际想要它们的形式的结果。所以这是我的(庞大的)查询,用于查找有关外键的信息。
几点说明:
-
用于生成
from_cols 和to_cols 的表达式可以在Postgres 9.4及更高版本上使用WITH ORDINALITY 而不是使用的窗口函数使用hackery大大简化。 -
这些相同的表达式依赖于查询规划器而不是改变
UNNEST 的返回结果顺序。我不认为它会,但我的数据集中没有任何多列外键来测试。添加9.4细节完全消除了这种可能性。 -
查询本身需要Postgres 9.0或更高版本(8.x在聚合函数中不允许
ORDER BY ) -
如果要使用列数组而不是逗号分隔的字符串,请将
STRING_AGG 替换为ARRAY_AGG 。
-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | 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; |
使用Keys引用的主键的名称并查询information_schema:
1 2 3 4 5 | 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'是外键引用的主键的名称。
简短而甜蜜
1 | SELECT * FROM information_schema.key_column_usage WHERE constraint_catalog=current_catalog AND TABLE_NAME='your_table_name' AND position_in_unique_constraint notnull; |
另一种方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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 ; |
我写了一个喜欢并经常使用的解决方案。该代码位于http://code.google.com/p/pgutils/。请参阅pgutils.foreign_keys视图。
不幸的是,输出太冗长而不包括在这里。但是,您可以在此处对数据库的公共版本进行尝试,如下所示:
1 | $ psql -h unison-db.org -U PUBLIC -d unison -c 'select * from pgutils.foreign_keys; |
这至少适用于8.3。如果需要,我预计在接下来的几个月内更新它。
-Reece
1 2 3 4 5 6 7 | 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 |
正确解决问题,使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 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 |
注意:在
我创建了一个小工具来查询,然后比较数据库模式:
将PostgreSQL数据库模式转储到文本
有关于FK的信息,但ollyc响应提供了更多细节。
注意:读取约束列时不要忘记列的顺序!
1 2 3 4 5 | 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) |
这就是我目前使用的,它将列出一个表,它是fkey约束[remove table子句,它将列出当前目录中的所有表]:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | 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') |