sql - 运行具有相互依赖性的 sql 脚本

标签 sql postgresql view

我有一个在后端使用 postgres 数据库的项目,我正在努力创建一个 Dockerfile,它可以自动设置数据库的本地开发实例。数据库包含大量函数,这些函数历来存储在上下文相关的 sql 文件中,例如用户.sql、公司.sql。这很好,因为无论何时进行更改,我都可以简单地执行相关的 sql 文件,REPLACE 所有 View 并删除/重新创建所有函数。

但是,当尝试在新的 postgres 实例上运行这些脚本时(在 CREATE 所有表之后),它们会失败,因为大多数 View /函数引用了其他尚未定义的 View 函数。

我已经开始调查是否有一个特定的顺序我可以运行脚本来避免这个问题,但由于它们在设计时并没有考虑到这个目的,所以这可能是不可能的,并且有大量的实体在玩,所以这很可能是一项不平凡的任务。

除了重构脚本之外,还有什么方法可以实现这一目标吗?

最佳答案

您可以编写一个简单的递归查询,从所有不依赖于其他 View 的 View 开始,然后递归地添加依赖于它们的 View 。然后按照正确的顺序输出这些 View 的 View 定义,你就得到了你的脚本:

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);

关于sql - 运行具有相互依赖性的 sql 脚本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57062573/

相关文章:

mysql - 主键本身可以包含重复项但具有唯一行吗?

php - PHP代码执行没有错误,插入操作成功,但数据不存在

java.lang.ClassNotFoundException : com. 微软.sqlserver.jdbc.SQLServerDriver

windows - 'psql' 不是内部或外部命令

visual-studio - 为什么当 Npgsql 团队发布的最新版本是 2.1.0 版时,Visual Studio 指的是 Npgsql 4.0.0.0 版?

swift - 以编程方式约束时,uiview 不绘制

android布局xml属性和定位...

mysql - 应用程序使用数据库授权和验证用户

java - 从 Spring Web 应用程序捕获用户名以供触发器使用

sql - PostgreSQL 如果存在则删除 View