【问题标题】:Copy schema on postgres with sql not working使用 sql 在 postgres 上复制模式不起作用
【发布时间】:2015-02-02 15:22:00
【问题描述】:

我在 postgres 上有多租户应用程序,为了创建帐户,我复制了一个模式“模板”并将其重命名为帐户数据。

我使用“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$

【问题讨论】:

    标签: sql postgresql multi-tenant


    【解决方案1】:

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

    如果序列的架构不在search path 中,则该架构作为序列名称的前缀出现,否则不显示。

    因此这个子句的结果,真假:

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

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

    为了不依赖它,你可以在块的持续时间内强制search_path,如:

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

    或者您可以将search_path 设置为源架构,在这种情况下,这些架构相关的default 子句可能根本不需要任何后处理。

    【讨论】:

      猜你喜欢
      • 2023-03-24
      • 2019-04-20
      • 2023-01-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-09
      相关资源
      最近更新 更多