【问题标题】:Copy schema and create new schema with different name in the same data base复制模式并在同一数据库中创建具有不同名称的新模式
【发布时间】:2010-03-03 11:06:07
【问题描述】:

我有办法在 postgres 的同一个数据库中复制现有架构并使用另一个名称生成新架构。

【问题讨论】:

标签: postgresql


【解决方案1】:

使用 pg_dump 将当前模式转储到 SQL 格式的文件中。打开文件,将 schemaname 替换为新名称,然后在数据库中执行此脚本以创建新 schema 和此 schema 中的所有其他对象。

【讨论】:

  • 我有一个问题:如果您在转储的 sql 文件中将 oldschema 替换为 newschema,似乎没有明确的方法只更改该文件中引用的文本架构,对吧?例如,如果我有一个带有像“hello”这样的常用词的架构,那么所有的 hello 实例(甚至与它的非架构相关实例)都将被替换?
【解决方案2】:

查看this PostgreSQL 的维基页面。它包含您需要的clone_schema 函数,但此函数仅克隆表。该页面引用了this 帖子,其中包含一个克隆模式所需的所有内容的函数。这个函数对我来说很好用,我设法用 JDBC API 来执行它。

但是当模式名称包含- 或大写字母时,我遇到了一些问题。经过研究,我发现问题的根源是quote_ident() 方法。我更改了 clone_schema 函数以使用任何模式名称。我在这里分享新功能,希望对某人有所帮助:

-- Function: clone_schema(text, text)

-- DROP FUNCTION clone_schema(text, text);

CREATE OR REPLACE FUNCTION clone_schema(
    source_schema text,
    dest_schema text,
    include_recs boolean)
  RETURNS void AS
$BODY$

--  This function will clone all sequences, tables, data, views & functions from any existing schema to a new one
-- SAMPLE CALL:
-- SELECT clone_schema('public', 'new_schema', TRUE);

DECLARE
  src_oid          oid;
  tbl_oid          oid;
  func_oid         oid;
  object           text;
  buffer           text;
  srctbl           text;
  default_         text;
  column_          text;
  qry              text;
  dest_qry         text;
  v_def            text;
  seqval           bigint;
  sq_last_value    bigint;
  sq_max_value     bigint;
  sq_start_value   bigint;
  sq_increment_by  bigint;
  sq_min_value     bigint;
  sq_cache_value   bigint;
  sq_log_cnt       bigint;
  sq_is_called     boolean;
  sq_is_cycled     boolean;
  sq_cycled        char(10);

BEGIN

-- Check that source_schema exists
  SELECT oid INTO src_oid
    FROM pg_namespace
   WHERE nspname = source_schema;
  IF NOT FOUND
    THEN 
    RAISE EXCEPTION 'source schema % does not exist!', source_schema;
    RETURN ;
  END IF;

  -- Check that dest_schema does not yet exist
  PERFORM nspname 
    FROM pg_namespace
   WHERE nspname = dest_schema;
  IF FOUND
    THEN 
    RAISE EXCEPTION 'dest schema % already exists!', dest_schema;
    RETURN ;
  END IF;

  EXECUTE 'CREATE SCHEMA "' || dest_schema || '"';

  -- Create sequences
  -- TODO: Find a way to make this sequence's owner is the correct table.
  FOR object IN
    SELECT sequence_name::text 
      FROM information_schema.sequences
     WHERE sequence_schema = source_schema
  LOOP
    EXECUTE 'CREATE SEQUENCE "' || dest_schema || '".' || quote_ident(object);
    srctbl := '"' || source_schema || '".' || quote_ident(object);

    EXECUTE 'SELECT last_value, max_value, start_value, increment_by, min_value, cache_value, log_cnt, is_cycled, is_called 
              FROM "' || source_schema || '".' || quote_ident(object) || ';' 
              INTO sq_last_value, sq_max_value, sq_start_value, sq_increment_by, sq_min_value, sq_cache_value, sq_log_cnt, sq_is_cycled, sq_is_called ; 

    IF sq_is_cycled 
      THEN 
        sq_cycled := 'CYCLE';
    ELSE
        sq_cycled := 'NO CYCLE';
    END IF;

    EXECUTE 'ALTER SEQUENCE "'   || dest_schema || '".' || quote_ident(object) 
            || ' INCREMENT BY ' || sq_increment_by
            || ' MINVALUE '     || sq_min_value 
            || ' MAXVALUE '     || sq_max_value
            || ' START WITH '   || sq_start_value
            || ' RESTART '      || sq_min_value 
            || ' CACHE '        || sq_cache_value 
            || sq_cycled || ' ;' ;

    buffer := '"' || dest_schema || '".' || quote_ident(object);
    IF include_recs 
        THEN
            EXECUTE 'SELECT setval( ''' || buffer || ''', ' || sq_last_value || ', ' || sq_is_called || ');' ; 
    ELSE
            EXECUTE 'SELECT setval( ''' || buffer || ''', ' || sq_start_value || ', ' || sq_is_called || ');' ;
    END IF;

  END LOOP;

-- Create tables 
  FOR object IN
    SELECT TABLE_NAME::text 
      FROM information_schema.tables 
     WHERE table_schema = source_schema
       AND table_type = 'BASE TABLE'

  LOOP
    buffer := '"' || dest_schema || '".' || quote_ident(object);
    EXECUTE 'CREATE TABLE ' || buffer || ' (LIKE "' || source_schema || '".' || quote_ident(object) 
        || ' INCLUDING ALL)';

    IF include_recs 
      THEN 
      -- Insert records from source table
      EXECUTE 'INSERT INTO ' || buffer || ' SELECT * FROM "' || source_schema || '".' || quote_ident(object) || ';';
    END IF;

    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 = object 
         AND column_default LIKE 'nextval(%"' || source_schema || '"%::regclass)'
    LOOP
      EXECUTE 'ALTER TABLE ' || buffer || ' ALTER COLUMN ' || column_ || ' SET DEFAULT ' || default_;
    END LOOP;

  END LOOP;

--  add FK constraint
  FOR qry IN
    SELECT 'ALTER TABLE "' || dest_schema || '".' || quote_ident(rn.relname) 
                          || ' ADD CONSTRAINT ' || quote_ident(ct.conname) || ' ' || pg_get_constraintdef(ct.oid) || ';'
      FROM pg_constraint ct
      JOIN pg_class rn ON rn.oid = ct.conrelid
     WHERE connamespace = src_oid
       AND rn.relkind = 'r'
       AND ct.contype = 'f'

    LOOP
      EXECUTE qry;

    END LOOP;


-- Create views 
  FOR object IN
    SELECT table_name::text,
           view_definition 
      FROM information_schema.views
     WHERE table_schema = source_schema

  LOOP
    buffer := '"' || dest_schema || '".' || quote_ident(object);
    SELECT view_definition INTO v_def
      FROM information_schema.views
     WHERE table_schema = source_schema
       AND table_name = quote_ident(object);

    EXECUTE 'CREATE OR REPLACE VIEW ' || buffer || ' AS ' || v_def || ';' ;

  END LOOP;

-- Create functions 
  FOR func_oid IN
    SELECT oid
      FROM pg_proc 
     WHERE pronamespace = src_oid

  LOOP      
    SELECT pg_get_functiondef(func_oid) INTO qry;
    SELECT replace(qry, source_schema, dest_schema) INTO dest_qry;
    EXECUTE dest_qry;

  END LOOP;

  RETURN; 

END;

$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
ALTER FUNCTION clone_schema(text, text, boolean)
  OWNER TO postgres;

【讨论】:

    【解决方案3】:

    我进行了一些测试,发现结果引用了源架构。所以这是我的改进版本:

    -- Function: clone_schema(source text, dest text, include_records boolean default true, show_details boolean default false)
    
    -- DROP FUNCTION clone_schema(text, text, boolean, boolean);
    
    CREATE OR REPLACE FUNCTION clone_schema(
      source_schema text,
      dest_schema text,
      include_recs boolean DEFAULT true,
      show_details boolean DEFAULT false)
      RETURNS void AS
    $BODY$
    
    --  This function will clone all sequences, tables, data, views & functions from any existing schema to a new one
    -- SAMPLE CALL:
    -- SELECT clone_schema('public', 'new_schema');
    -- SELECT clone_schema('public', 'new_schema', TRUE);
    -- SELECT clone_schema('public', 'new_schema', TRUE, TRUE);
    
    DECLARE
      src_oid          oid;
      tbl_oid          oid;
      func_oid         oid;
      object           text;
      buffer           text;
      srctbl           text;
      default_         text;
      column_          text;
      qry              text;
      xrec             record;
      dest_qry         text;
      v_def            text;
      seqval           bigint;
      sq_last_value    bigint;
      sq_max_value     bigint;
      sq_start_value   bigint;
      sq_increment_by  bigint;
      sq_min_value     bigint;
      sq_cache_value   bigint;
      sq_log_cnt       bigint;
      sq_is_called     boolean;
      sq_is_cycled     boolean;
      sq_cycled        char(10);
      rec              record;
      source_schema_dot text = source_schema || '.';
      dest_schema_dot text = dest_schema || '.';
    
    BEGIN
    
      -- Check that source_schema exists
      SELECT oid INTO src_oid
      FROM pg_namespace
      WHERE nspname = quote_ident(source_schema);
      IF NOT FOUND
      THEN
        RAISE NOTICE 'source schema % does not exist!', source_schema;
        RETURN ;
      END IF;
    
      -- Check that dest_schema does not yet exist
      PERFORM nspname
      FROM pg_namespace
      WHERE nspname = quote_ident(dest_schema);
      IF FOUND
      THEN
        RAISE NOTICE 'dest schema % already exists!', dest_schema;
        RETURN ;
      END IF;
    
      EXECUTE 'CREATE SCHEMA ' || quote_ident(dest_schema) ;
    
      -- Defaults search_path to destination schema
      PERFORM set_config('search_path', dest_schema, true);
    
      -- Create sequences
      -- TODO: Find a way to make this sequence's owner is the correct table.
      FOR object IN
      SELECT sequence_name::text
      FROM information_schema.sequences
      WHERE sequence_schema = quote_ident(source_schema)
      LOOP
        EXECUTE 'CREATE SEQUENCE ' || quote_ident(dest_schema) || '.' || quote_ident(object);
        srctbl := quote_ident(source_schema) || '.' || quote_ident(object);
    
        EXECUTE 'SELECT last_value, max_value, start_value, increment_by, min_value, cache_value, log_cnt, is_cycled, is_called
                  FROM ' || quote_ident(source_schema) || '.' || quote_ident(object) || ';'
        INTO sq_last_value, sq_max_value, sq_start_value, sq_increment_by, sq_min_value, sq_cache_value, sq_log_cnt, sq_is_cycled, sq_is_called ;
    
        IF sq_is_cycled
        THEN
          sq_cycled := 'CYCLE';
        ELSE
          sq_cycled := 'NO CYCLE';
        END IF;
    
        EXECUTE 'ALTER SEQUENCE '   || quote_ident(dest_schema) || '.' || quote_ident(object)
                || ' INCREMENT BY ' || sq_increment_by
                || ' MINVALUE '     || sq_min_value
                || ' MAXVALUE '     || sq_max_value
                || ' START WITH '   || sq_start_value
                || ' RESTART '      || sq_min_value
                || ' CACHE '        || sq_cache_value
                || sq_cycled || ' ;' ;
    
        buffer := quote_ident(dest_schema) || '.' || quote_ident(object);
        IF include_recs
        THEN
          EXECUTE 'SELECT setval( ''' || buffer || ''', ' || sq_last_value || ', ' || sq_is_called || ');' ;
        ELSE
          EXECUTE 'SELECT setval( ''' || buffer || ''', ' || sq_start_value || ', ' || sq_is_called || ');' ;
        END IF;
        IF show_details THEN RAISE NOTICE 'Sequence created: %', object; END IF;
      END LOOP;
    
      -- Create tables
      FOR object IN
      SELECT TABLE_NAME::text
      FROM information_schema.tables
      WHERE table_schema = quote_ident(source_schema)
            AND table_type = 'BASE TABLE'
    
      LOOP
        buffer := dest_schema || '.' || quote_ident(object);
        EXECUTE 'CREATE TABLE ' || buffer || ' (LIKE ' || quote_ident(source_schema) || '.' || quote_ident(object)
                || ' INCLUDING ALL)';
    
        IF include_recs
        THEN
          -- Insert records from source table
          EXECUTE 'INSERT INTO ' || buffer || ' SELECT * FROM ' || quote_ident(source_schema) || '.' || quote_ident(object) || ';';
        END IF;
    
        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 = object
              AND column_default LIKE 'nextval(%' || quote_ident(source_schema) || '%::regclass)'
        LOOP
          EXECUTE 'ALTER TABLE ' || buffer || ' ALTER COLUMN ' || column_ || ' SET DEFAULT ' || default_;
        END LOOP;
    
        IF show_details THEN RAISE NOTICE 'base table created: %', object; END IF;
    
      END LOOP;
    
      --  add FK constraint
      FOR xrec IN
      SELECT ct.conname as fk_name, rn.relname as tb_name,  'ALTER TABLE ' || quote_ident(dest_schema) || '.' || quote_ident(rn.relname)
             || ' ADD CONSTRAINT ' || quote_ident(ct.conname) || ' ' || replace(pg_get_constraintdef(ct.oid), source_schema_dot, '') || ';' as qry
      FROM pg_constraint ct
        JOIN pg_class rn ON rn.oid = ct.conrelid
      WHERE connamespace = src_oid
            AND rn.relkind = 'r'
            AND ct.contype = 'f'
    
      LOOP
        IF show_details THEN RAISE NOTICE 'Creating FK constraint %.%...', xrec.tb_name, xrec.fk_name; END IF;
        --RAISE NOTICE 'DEF: %', xrec.qry;
        EXECUTE xrec.qry;
      END LOOP;
    
      -- Create functions
      FOR xrec IN
      SELECT proname as func_name, oid as func_oid
      FROM pg_proc
      WHERE pronamespace = src_oid
    
      LOOP
        IF show_details THEN RAISE NOTICE 'Creating function %...', xrec.func_name; END IF;
        SELECT pg_get_functiondef(xrec.func_oid) INTO qry;
        SELECT replace(qry, source_schema_dot, '') INTO dest_qry;
        EXECUTE dest_qry;
      END LOOP;
    
      -- add Table Triggers
      FOR rec IN
      SELECT
        trg.tgname AS trigger_name,
        tbl.relname AS trigger_table,
    
        CASE
        WHEN trg.tgenabled='O' THEN 'ENABLED'
        ELSE 'DISABLED'
        END AS status,
        CASE trg.tgtype::integer & 1
        WHEN 1 THEN 'ROW'::text
        ELSE 'STATEMENT'::text
        END AS trigger_level,
        CASE trg.tgtype::integer & 66
        WHEN 2 THEN 'BEFORE'
        WHEN 64 THEN 'INSTEAD OF'
        ELSE 'AFTER'
        END AS action_timing,
        CASE trg.tgtype::integer & cast(60 AS int2)
        WHEN 16 THEN 'UPDATE'
        WHEN 8 THEN 'DELETE'
        WHEN 4 THEN 'INSERT'
        WHEN 20 THEN 'INSERT OR UPDATE'
        WHEN 28 THEN 'INSERT OR UPDATE OR DELETE'
        WHEN 24 THEN 'UPDATE OR DELETE'
        WHEN 12 THEN 'INSERT OR DELETE'
        WHEN 32 THEN 'TRUNCATE'
        END AS trigger_event,
        'EXECUTE PROCEDURE ' ||  (SELECT nspname FROM pg_namespace where oid = pc.pronamespace )
        || '.' || proname || '('
        || regexp_replace(replace(trim(trailing '\000' from encode(tgargs,'escape')), '\000',','),'{(.+)}','''{\1}''','g')
        || ')' as action_statement
    
      FROM pg_trigger trg
        JOIN pg_class tbl on trg.tgrelid = tbl.oid
        JOIN pg_proc pc ON pc.oid = trg.tgfoid
      WHERE trg.tgname not like 'RI_ConstraintTrigger%'
            AND trg.tgname not like 'pg_sync_pg%'
            AND tbl.relnamespace = (SELECT oid FROM pg_namespace where nspname = quote_ident(source_schema) )
    
      LOOP
        buffer := dest_schema || '.' || quote_ident(rec.trigger_table);
        IF show_details THEN RAISE NOTICE 'Creating trigger % % % ON %...', rec.trigger_name, rec.action_timing, rec.trigger_event, rec.trigger_table; END IF;
        EXECUTE 'CREATE TRIGGER ' || rec.trigger_name || ' ' || rec.action_timing
                || ' ' || rec.trigger_event || ' ON ' || buffer || ' FOR EACH '
                || rec.trigger_level || ' ' || replace(rec.action_statement, source_schema_dot, '');
    
      END LOOP;
    
      -- Create views
      FOR object IN
      SELECT table_name::text,
        view_definition
      FROM information_schema.views
      WHERE table_schema = quote_ident(source_schema)
    
      LOOP
        buffer := dest_schema || '.' || quote_ident(object);
        SELECT replace(view_definition, source_schema_dot, '') INTO v_def
        FROM information_schema.views
        WHERE table_schema = quote_ident(source_schema)
              AND table_name = quote_ident(object);
        IF show_details THEN RAISE NOTICE 'Creating view % AS %', object, regexp_replace(v_def, '[\n\r]+', ' ', 'g'); END IF;
        EXECUTE 'CREATE OR REPLACE VIEW ' || buffer || ' AS ' || v_def || ';' ;
    
      END LOOP;
    
      RETURN;
    
    END;
    
    $BODY$
    LANGUAGE plpgsql VOLATILE
    COST 100;
    

    【讨论】:

      【解决方案4】:

      你可以使用这个简单的脚本:

      DO LANGUAGE plpgsql
      $body$
      DECLARE
         old_schema NAME = 'src_schema';
         new_schema NAME = 'dst_schema';
         tbl TEXT;
         sql TEXT;
      BEGIN
        EXECUTE format('CREATE SCHEMA IF NOT EXISTS %I', new_schema);
      
        FOR tbl IN
          SELECT table_name
          FROM information_schema.tables
          WHERE table_schema=old_schema
        LOOP
          sql := format(
                  'CREATE TABLE IF NOT EXISTS %I.%I '
                  '(LIKE %I.%I INCLUDING INDEXES INCLUDING CONSTRAINTS)'
                  , new_schema, tbl, old_schema, tbl);
      
          EXECUTE sql;
      
          sql := format(
                  'INSERT INTO %I.%I '
                  'SELECT * FROM %I.%I'
                  , new_schema, tbl, old_schema, tbl);
      
          EXECUTE sql;
        END LOOP;
      END
      $body$;
      

      【讨论】:

        【解决方案5】:
        • 如果复制模式是指复制数据库,那么只需使用TEMPLATE 选项来创建副本:CREATE DATABASE dbname_target TEMPLATE dbname_source;

        这也会复制数据。因此,如果您需要许多副本,您可能需要创建自己的模板。见Template Databases

        • 如果您只需要架构,那么我建议您将 DB DDL 脚本置于源代码控制之下(无论如何这都是一个好主意),并有一个单独的(模板化的)脚本来为您创建架构。基本上,您有一个 SQL 文件,在其中将 ${schema_name} 替换为您的新模式名称,然后在数据库上执行此脚本。这样,如果您对此 schema 进行更改,您还可以使用脚本将架构更新到新版本,在这种情况下,您必须为每个用户架构执行此操作。

        【讨论】:

        • 您好,我有一个包含多个模式的数据库,我的要求是,我保留一个模式作为基础,并希望根据同一数据库中的基本模式结构为每个用户创建不同的模式
        • 很抱歉评论旧答案,但是,这个答案与 Postgresql 模式无关。
        【解决方案6】:

        使用@IdanDavidi 的solution,我能够解决序列由源架构拥有并引用源架构而不是目标架构的情况。

        -- Function: clone_schema(text, text)
        
        -- DROP FUNCTION clone_schema(text, text);
        
        CREATE OR REPLACE FUNCTION clone_schema(
            source_schema text,
            dest_schema text,
            include_recs boolean)
          RETURNS void AS
        $BODY$
        
        --  This function will clone all sequences, tables, data, views & functions from any existing schema to a new one
        -- SAMPLE CALL:
        -- SELECT clone_schema('public', 'new_schema', TRUE);
        
        DECLARE
          src_oid          oid;
          tbl_oid          oid;
          func_oid         oid;
          table_rec        record;
          seq_rec          record;
          object           text;
          sequence_        text;
          table_           text;
          buffer           text;
          seq_buffer       text;
          table_buffer     text;
          srctbl           text;
          default_         text;
          column_          text;
          qry              text;
          dest_qry         text;
          v_def            text;
          seqval           bigint;
          sq_last_value    bigint;
          sq_max_value     bigint;
          sq_start_value   bigint;
          sq_increment_by  bigint;
          sq_min_value     bigint;
          sq_cache_value   bigint;
          sq_log_cnt       bigint;
          sq_is_called     boolean;
          sq_is_cycled     boolean;
          sq_cycled        char(10);
        
        BEGIN
        
        -- Check that source_schema exists
          SELECT oid INTO src_oid
            FROM pg_namespace
           WHERE nspname = source_schema;
          IF NOT FOUND
            THEN
            RAISE EXCEPTION 'source schema % does not exist!', source_schema;
            RETURN ;
          END IF;
        
        -- Check that dest_schema does not yet exist
          PERFORM nspname
            FROM pg_namespace
           WHERE nspname = dest_schema;
          IF FOUND
            THEN
            RAISE EXCEPTION 'dest schema % already exists!', dest_schema;
            RETURN ;
          END IF;
        
          EXECUTE 'CREATE SCHEMA "' || dest_schema || '"';
        
        -- Create tables
          FOR object IN
            SELECT TABLE_NAME::text
              FROM information_schema.tables
             WHERE table_schema = source_schema
               AND table_type = 'BASE TABLE'
        
          LOOP
            buffer := '"' || dest_schema || '".' || quote_ident(object);
            EXECUTE 'CREATE TABLE ' || buffer || ' (LIKE "' || source_schema || '".' || quote_ident(object)
                || ' INCLUDING ALL);';
        
            IF include_recs
              THEN
              -- Insert records from source table
              EXECUTE 'INSERT INTO ' || buffer || ' SELECT * FROM "' || source_schema || '".' || quote_ident(object) || ';';
            END IF;
        
          END LOOP;
        
        --  add FK constraint
          FOR qry IN
            SELECT 'ALTER TABLE "' || dest_schema || '".' || quote_ident(rn.relname)
                    || ' ADD CONSTRAINT ' || quote_ident(ct.conname) || ' ' || pg_get_constraintdef(ct.oid) || ';'
              FROM pg_constraint ct
              JOIN pg_class rn ON rn.oid = ct.conrelid
             WHERE connamespace = src_oid
               AND rn.relkind = 'r'
               AND ct.contype = 'f'
        
            LOOP
              EXECUTE qry;
        
            END LOOP;
        
        -- Create sequences
          FOR seq_rec IN
            SELECT
              s.sequence_name::text,
              table_name,
              column_name
            FROM information_schema.sequences s
            JOIN (
              SELECT
                substring(column_default from E'^nextval\\(''(?:[^"'']?.*["'']?\\.)?([^'']*)''(?:::text|::regclass)?\\)')::text as seq_name,
                table_name,
                column_name
              FROM information_schema.columns
              WHERE column_default LIKE 'nextval%'
                AND table_schema = source_schema
            ) c ON c.seq_name = s.sequence_name
            WHERE sequence_schema = source_schema
          LOOP
            seq_buffer := quote_ident(dest_schema) || '.' || quote_ident(seq_rec.sequence_name);
        
            EXECUTE 'CREATE SEQUENCE ' || seq_buffer || ';';
        
            qry := 'SELECT last_value, max_value, start_value, increment_by, min_value, cache_value, log_cnt, is_cycled, is_called
                      FROM "' || source_schema || '".' || quote_ident(seq_rec.sequence_name) || ';';
            EXECUTE qry INTO sq_last_value, sq_max_value, sq_start_value, sq_increment_by, sq_min_value, sq_cache_value, sq_log_cnt, sq_is_cycled, sq_is_called ;
        
            IF sq_is_cycled
              THEN
                sq_cycled := 'CYCLE';
            ELSE
                sq_cycled := 'NO CYCLE';
            END IF;
        
            EXECUTE 'ALTER SEQUENCE '   || seq_buffer
                    || ' INCREMENT BY ' || sq_increment_by
                    || ' MINVALUE '     || sq_min_value
                    || ' MAXVALUE '     || sq_max_value
                    || ' START WITH '   || sq_start_value
                    || ' RESTART '      || sq_min_value
                    || ' CACHE '        || sq_cache_value
                    || ' OWNED BY '     || quote_ident(dest_schema ) || '.'
                                        || quote_ident(seq_rec.table_name) || '.'
                                        || quote_ident(seq_rec.column_name) || ' '
                    || sq_cycled || ' ;' ;
        
            IF include_recs
                THEN
                    EXECUTE 'SELECT setval( ''' || seq_buffer || ''', ' || sq_last_value || ', ' || sq_is_called || ');' ;
            ELSE
                    EXECUTE 'SELECT setval( ''' || seq_buffer || ''', ' || sq_start_value || ', ' || sq_is_called || ');' ;
            END IF;
        
            table_buffer := quote_ident(dest_schema) || '.' || quote_ident(seq_rec.table_name);
        
            FOR table_rec IN
              SELECT column_name::text AS column_,
                     REPLACE(column_default::text, source_schema, quote_ident(dest_schema)) AS default_
                FROM information_schema.COLUMNS
               WHERE table_schema = dest_schema
                 AND TABLE_NAME = seq_rec.table_name
                 AND column_default LIKE 'nextval(%' || seq_rec.sequence_name || '%::regclass)'
            LOOP
              EXECUTE 'ALTER TABLE ' || table_buffer || ' ALTER COLUMN ' || table_rec.column_ || ' SET DEFAULT nextval(' || quote_literal(seq_buffer) || '::regclass);';
            END LOOP;
        
          END LOOP;
        
        -- Create views
          FOR object IN
            SELECT table_name::text,
                   view_definition
              FROM information_schema.views
             WHERE table_schema = source_schema
        
          LOOP
            buffer := '"' || dest_schema || '".' || quote_ident(object);
            SELECT view_definition INTO v_def
              FROM information_schema.views
             WHERE table_schema = source_schema
               AND table_name = quote_ident(object);
        
            EXECUTE 'CREATE OR REPLACE VIEW ' || buffer || ' AS ' || v_def || ';' ;
        
          END LOOP;
        
        -- Create functions
          FOR func_oid IN
            SELECT oid
              FROM pg_proc
             WHERE pronamespace = src_oid
        
          LOOP
            SELECT pg_get_functiondef(func_oid) INTO qry;
            SELECT replace(qry, source_schema, dest_schema) INTO dest_qry;
            EXECUTE dest_qry;
        
          END LOOP;
        
          RETURN;
        
        END;
        
        $BODY$
          LANGUAGE plpgsql VOLATILE
          COST 100;
        

        【讨论】:

          【解决方案7】:

          这似乎是我想出的最佳解决方案。

          这个想法是使用带有 -O(无所有者)和 -o(oids)选项的 pg_dump 来获得纯文本输出没有源架构和所有者信息。

          这样的输出我通过 sed 过滤替换默认条目

          SET search_path = source_schema, pg_catalog;
          

          使用命令创建新架构并为其设置默认搜索路径

          CREATE SCHEMA new_schema;
          SET search_path = new_schema, pg_catalog;
          

          之后,我将流重定向到 psql 记录到所需的用户和数据库,架构副本将传输到该数据库。

          将架构“public”复制到同一数据库“b1”中的架构“2016”的最终命令如下所示:

          pg_dump -U postgres -Oo -n public -d b1 | sed 's/SET search_path = public, pg_catalog;/CREATE SCHEMA "2016";SET search_path = "2016", pg_catalog;/' | psql -U postgres -d b1
          

          请注意,GRANTS 不会从源架构转移到新架构。

          【讨论】:

            【解决方案8】:

            如果您可以只使用表和列(没有约束、键等),这个简单的脚本可能会有所帮助

            DO LANGUAGE plpgsql
            $body$
            DECLARE
               old_schema NAME = 'src_schema';
               new_schema NAME = 'dst_schema';
               tbl TEXT;
               sql TEXT;
            BEGIN
              EXECUTE format('CREATE SCHEMA IF NOT EXISTS %I', new_schema);
            
              FOR tbl IN
                SELECT table_name
                FROM information_schema.tables
                WHERE table_schema=old_schema
              LOOP
                sql := format(
                        'CREATE TABLE IF NOT EXISTS %I.%I '
                        'AS '
                        'SELECT * FROM %I.%I'
                        , new_schema, tbl, old_schema, tbl);
                raise notice 'Sql: %', sql;
            
                EXECUTE sql;
              END LOOP;
            END
            $body$;
            

            【讨论】:

              猜你喜欢
              • 2022-11-19
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-04-09
              • 1970-01-01
              • 2014-01-21
              • 1970-01-01
              相关资源
              最近更新 更多