sql - 使用 sql 不工作在 postgres 上复制模式

标签 sql postgresql multi-tenant

我在 postgres 上有 Multi-Tenancy 应用程序,为了创建帐户,我复制了一个模式"template"并为帐户数据重命名它。

我使用“sql”变量来复制模式“_template”。 当我执行此操作时,一切正常,但具有 DEFAULT 属性的列未被替换。 但是在 pgAdmin 中直接执行 sql 时工作正常。

例子: “id bigint NOT NULL DEFAULT nextval('_template.table_id_seq'::regclass)” 这个 _template.table_id_seq... 应该是 [schemaname].table_id_seq

String sql = new String(
"DO " +
"$do$ " +
"DECLARE " +
"   objeto text; " +
"   buffer text; " +
"   source_schema text; " +
"   dest_schema text; " +
"   default_ text; " +
"   column_ text; " +
"BEGIN " +
" " +
"   source_schema := '_template'; " +
"   dest_schema   := '" + schema + "'; " +
" " +
"EXECUTE 'CREATE SCHEMA ' || dest_schema ; " +
" " +
"   FOR objeto IN " +
"       SELECT sequence_name::text FROM information_schema.SEQUENCES WHERE sequence_schema = source_schema " +
"   LOOP " +
"EXECUTE 'CREATE SEQUENCE ' || dest_schema || '.' || objeto; " +
"   END LOOP; " +
" " +
" " +
"   FOR objeto IN " +
"       SELECT table_name::text FROM information_schema.TABLES WHERE table_schema = source_schema " +
"   LOOP         " +
"       buffer := dest_schema || '.' || objeto; " +
"       EXECUTE 'CREATE TABLE ' || buffer || ' (LIKE ' || source_schema || '.' || objeto || ' INCLUDING CONSTRAINTS INCLUDING INDEXES INCLUDING DEFAULTS)'; " +
"FOR column_, default_ IN " +
"           SELECT column_name::text, REPLACE( column_default::text, source_schema, dest_schema ) FROM " +
"               information_schema.COLUMNS WHERE table_schema = source_schema AND table_name = objeto AND column_default LIKE 'nextval(%' || source_schema || '%)' " +
"       LOOP " +
"EXECUTE 'ALTER TABLE ' || buffer || ' ALTER COLUMN ' || column_ || ' SET DEFAULT ' || default_; " +
"       END LOOP; " +
" " +
"   END LOOP; " +
"END " +
"$do$    " 
);

这里是一个sql var输出的例子

DO $do$ 
DECLARE     
    objeto text;    
    buffer text;    
    source_schema text;     
    dest_schema text;   
    default_ text;  
    column_ text; 
BEGIN  
    source_schema := '_template';   
    dest_schema   := 'schemacopied';  

    EXECUTE 'CREATE SCHEMA ' || dest_schema ;   

    FOR objeto IN       
        SELECT sequence_name::text FROM information_schema.SEQUENCES WHERE sequence_schema = source_schema 

    LOOP 
        EXECUTE 'CREATE SEQUENCE ' || dest_schema || '.' || objeto;     
    END LOOP;       

    FOR objeto IN       
        SELECT table_name::text FROM information_schema.TABLES WHERE table_schema = source_schema   
    LOOP                
        buffer := dest_schema || '.' || objeto;         
        EXECUTE 'CREATE TABLE ' || buffer || ' (LIKE ' || source_schema || '.' || objeto || ' INCLUDING CONSTRAINTS INCLUDING INDEXES INCLUDING DEFAULTS)'; 

        FOR column_, default_ IN            
            SELECT column_name::text, REPLACE( column_default::text, source_schema, dest_schema ) FROM 
            information_schema.COLUMNS WHERE table_schema = dest_schema AND table_name = objeto AND column_default LIKE 'nextval(%' || source_schema || '%)'        

        LOOP 
            EXECUTE 'ALTER TABLE ' || buffer || ' ALTER COLUMN ' || column_ || ' SET DEFAULT ' || default_;         
        END LOOP;   
    END LOOP; 
END $do$

最佳答案

information_schema.COLUMNS.column_default 中引用的 nextval(...) 表达式是动态生成的,以根据当前 包含或排除架构名称搜索路径

如果序列的模式不在搜索路径中,该模式将作为序列名称的前缀出现,否则不会出现。

因此该子句的结果,真或假:

column_default LIKE 'nextval(%' || source_schema || '%)'

确实取决于 search_path,这可以解释为什么它在某些情况下(您在 pgAdmin 中的测试)有效,而在其他情况下无效。

为了不依赖它,您可以在 block 的持续时间内强制使用 search_path,如:

DO $$
BEGIN
  SET LOCAL search_path TO public;
  ...
  ...
END
$$ LANGUAGE plpgsql;

或者您可以将 search_path 设置为源模式,在这种情况下,这些与模式相关的 default 可能根本不需要任何后处理条款。

关于sql - 使用 sql 不工作在 postgres 上复制模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28280953/

相关文章:

mongodb - Spring Data MongoDB 基于集合的 Multi-Tenancy

sql - 处理 PL-SQL 异常并继续循环

node.js - 无法安装 node-postgres

sql - 具有多列输出的postgresql函数

postgresql - Odoo 12 编码 latin1 无法解析

database - 为每个客户端使用单个数据库有什么好处?

python - 在 django Multi-Tenancy 中显示主页

php - 将购物车和用户数据插入订单系统的 mysql

sql - 如何在存储过程的 IN 过滤器内将 nvarchar 转换为 int

mysql - 获取最新条目并加入另一张表