我有一个在后端使用postgres数据库的项目,并且我正在创建一个Dockerfile,该文件可以自动设置数据库的本地开发实例。该数据库包含大量功能,并且这些功能在历史上一直存储在上下文相关的sql文件中,例如,users.sql,companys.sql。这样做很好,因为每当进行更改时,我都可以简单地执行REPLACE所有视图和删除/重新创建所有函数的相关sql文件。
REPLACE
但是,当尝试在一个新的postgres实例上运行这些脚本时(在CREATE所有表之后),它们会失败,因为大多数视图/函数都引用了尚未定义的其他视图函数。
CREATE
我已经开始研究是否可以按特定顺序运行脚本来避免此问题,但是由于考虑到这些脚本的设计目的并非出于此目的,因此这可能是不可能的,并且存在大量实体,因此是最重要的任务。
除了重组脚本之外,还有什么方法可以实现这一目标?
您可以编写一个简单的递归查询,该查询以不依赖于其他视图的所有视图开头,然后以递归方式添加依赖于这些视图的视图。然后以正确的顺序输出这些视图的视图定义,您已经获得了脚本:
WITH RECURSIVE viewids AS ( /* all views that don't depend on other views */ SELECT t.oid, 1 as level FROM pg_class t JOIN pg_rewrite AS r ON r.ev_class = t.oid WHERE r.rulename = '_RETURN' AND t.relkind = 'v' AND t.relnamespace NOT IN ('pg_catalog'::regnamespace, 'information_schema'::regnamespace, 'pg_toast'::regnamespace) AND NOT EXISTS ( /* depends on a view */ SELECT 1 FROM pg_depend AS d JOIN pg_class AS t2 ON d.refobjid = t2.oid WHERE d.objid = r.oid AND d.classid = 'pg_rewrite'::regclass AND d.refclassid = 'pg_class'::regclass AND d.deptype = 'n' AND d.refobjsubid <> 0 AND t2.relkind = 'v' ) AND NOT EXISTS ( /* depends on an extension */ SELECT 1 FROM pg_depend WHERE objid = t.oid AND classid = 'pg_class'::regclass AND refclassid = 'pg_extension'::regclass AND deptype = 'e' ) UNION ALL /* all views that depend on these views */ SELECT t.oid, viewids.level + 1 FROM pg_class AS t JOIN pg_rewrite AS r ON r.ev_class = t.oid JOIN pg_depend AS d ON d.objid = r.oid JOIN viewids ON viewids.oid = d.refobjid WHERE t.relkind = 'v' AND r.rulename = '_RETURN' AND d.classid = 'pg_rewrite'::regclass AND d.refclassid = 'pg_class'::regclass AND d.deptype = 'n' AND d.refobjsubid <> 0 ) /* order the views by level, eliminating duplicates */ SELECT format('CREATE VIEW %s AS%s', oid::regclass, pg_get_viewdef(oid::regclass)) FROM viewids GROUP BY oid ORDER BY max(level);