不行。SQL视图不能用作外键的参照表,因其是虚拟表、无物理存储、不支持主键/唯一约束,数据库在DDL解析阶段即拒绝;所有主流DBMS均不支持,本质是外键依赖的参照完整性需基表的稳定行标识与事务保障。

视图本身不参与外键约束检查,也不能替代外键的级联行为;但它能帮你快速查出哪些表用了外键、怎么级联、是否启用,只需查系统目录视图即可。
查外键定义和级联动作用 pg_constraint
PostgreSQL 把所有约束(包括外键)存在 pg_constraint 里。外键的级联动作(ON DELETE / ON UPDATE)就藏在 confupdtype 和 confdeltype 字段里,值是单字符编码:
-
a= NO ACTION(默认,不触发) -
r= RESTRICT(拒绝父行删除/更新) -
c= CASCADE(级联删除/更新) -
n= SET NULL -
d= SET DEFAULT
常用查询示例:
SELECT conname AS constraint_name, conrelid::regclass AS table_name, confrelid::regclass AS referenced_table, CASE confdeltype WHEN 'c' THEN 'CASCADE' WHEN 'r' THEN 'RESTRICT' ELSE 'NO ACTION' END AS on_delete, CASE confupdtype WHEN 'c' THEN 'CASCADE' WHEN 'r' THEN 'RESTRICT' ELSE 'NO ACTION' END AS on_update FROM pg_constraint WHERE contype = 'f';
注意:conrelid::regclass 能把 OID 变成可读表名,比直接查 pg_class 更省事;但若约束跨 schema,需确保当前 search_path 包含目标 schema,否则显示为数字 OID。
查外键列映射关系用 pg_attribute + pg_constraint
仅知道表名不够,你还得知道哪几列参与了外键引用。外键列序号存在 conkey(本表列),confkey(被引用表列)里,都是 int2vector 类型,得用 generate_subscripts 或数组展开才能对齐。
更稳妥的做法是建一个轻量视图封装这个逻辑:
CREATE VIEW foreign_key_details AS SELECT c.conname, t.relname AS table_name, a.attname AS column_name, ft.relname AS ref_table, fa.attname AS ref_column, c.confupdtype, c.confdeltype FROM pg_constraint c JOIN pg_class t ON c.conrelid = t.oid JOIN pg_class ft ON c.confrelid = ft.oid JOIN pg_attribute a ON a.attnum = ANY(c.conkey) AND a.attrelid = t.oid JOIN pg_attribute fa ON fa.attnum = ANY(c.confkey) AND fa.attrelid = ft.oid WHERE c.contype = 'f';
之后直接 SELECT * FROM foreign_key_details WHERE table_name = 'orders'; 就能看清订单表每个外键连的是谁、哪几列、怎么级联。
容易踩的坑:conkey 和 confkey 是有序数组,但 ANY() 会打乱顺序 —— 所以上面视图其实只适用于单列外键。多列外键必须用 generate_subscripts(c.conkey, 1) 对齐索引,否则列和引用列会错位。
为什么不能靠视图实现级联逻辑?
视图只是查询封装,不改变数据写入路径。即使你创建了一个包含 JOIN 的视图,执行 UPDATE 或 DELETE 时 PostgreSQL 仍按基础表的外键约束规则走 —— 视图不会自动触发 ON DELETE CASCADE,也不会绕过 RESTRICT 检查。
换句话说:DELETE FROM orders WHERE id = 123 是否级联删掉 order_items,取决于 order_items.order_id 外键定义里的 ON DELETE,跟有没有视图、视图里有没有 JOIN order_items 完全无关。
真正能“简化级联检查”的,是用视图把约束元数据变成人类可读格式,而不是让视图去执行级联动作。
系统目录视图别直接改,也别加索引
pg_constraint、pg_class、pg_attribute 都是只读系统目录视图,不能 INSERT/UPDATE,也不支持在上面建索引。想加速查询,只能靠合理使用 WHERE 条件(比如先过滤 contype = 'f' 再 join)、或物化你常用的摘要视图(如上面的 foreign_key_details),但要注意物化视图需手动刷新且不自动同步 DDL 变更。
最常被忽略的一点:系统目录字段类型很多不是字符串(比如 conkey 是 smallint[],confdeltype 是 "char"),直接 SELECT * 看不出含义,必须查 pg_constraint 的文档或用 ::regclass / CASE 显式转换。

















