如何在PostgreSQL中复制模式

时间:2013-08-13 18:25:44

标签: postgresql database-schema foreign-key-relationship postgresql-9.1

我有一个包含架构publicschema_A的数据库。我需要创建一个与schema_b结构相同的新架构schema_a。 我找到了下面的函数,问题是它不会复制外键约束。

CREATE OR REPLACE FUNCTION clone_schema(source_schema text, dest_schema text)
  RETURNS void AS
$BODY$
DECLARE
  object text;
  buffer text;
  default_ text;
  column_ text;
BEGIN
  EXECUTE 'CREATE SCHEMA ' || dest_schema ;

  -- 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 || '.' || object;
  END LOOP;

  FOR object IN
    SELECT table_name::text FROM information_schema.TABLES WHERE table_schema = source_schema
  LOOP
    buffer := dest_schema || '.' || object;
    EXECUTE 'CREATE TABLE ' || buffer || ' (LIKE ' || source_schema || '.' || object || ' 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 = object AND column_default LIKE 'nextval(%' || source_schema || '%::regclass)'
    LOOP
      EXECUTE 'ALTER TABLE ' || buffer || ' ALTER COLUMN ' || column_ || ' SET DEFAULT ' || default_;
    END LOOP;
  END LOOP;

END;
$BODY$  LANGUAGE plpgsql

如何使用外键约束克隆/复制schema_A

5 个答案:

答案 0 :(得分:21)

您可以在不使用文件的情况下从命令行执行此操作:

pg_dump -U user --schema='fromschema' database | sed 's/fromschmea/toschema/g' | psql -U user -d database

注意,这会搜索并替换作为您的架构名称的所有字符串,因此可能会影响您的数据

答案 1 :(得分:13)

我会使用pg_dump转储没有数据的架构:

-s
--schema-only
     

仅转储对象定义(架构),而不转储数据。

     

此选项与--data-only相反。它类似于,但由于历史原因不同,指定--section=pre-data --section=post-data

     

(不要将此与--schema选项混淆,后者使用不同含义的“schema”一词。)

     

要仅为数据库中的表子集排除表数据,请参阅--exclude-table-data

pg_dump $DB -p $PORT -n $SCHEMA -s -f filename.pgsql

然后重命名转储中的架构(搜索和替换)并使用psql将其恢复。

psql $DB -f filename.pgsql

引用其他模式中的表的外键约束将被复制为指向相同的模式。
相同架构中的表的引用指向复制架构中的相应表。

答案 2 :(得分:4)

派对有点晚了但是,这里的一些SQL可以帮助你:

获取架构oid:

namespace_id = SELECT oid 
                  FROM pg_namespace 
                 WHERE nspname = '<schema name>';

获取表格

table_id = SELECT relfilenode 
                FROM pg_class 
               WHERE relnamespace = '<namespace_id>' AND relname = '<table_name>'

获取外键约束:

SELECT con.conname, pg_catalog.pg_get_constraintdef(con.oid) AS condef 
  FROM pg_catalog.pg_constraint AS con 
  JOIN pg_class AS cl ON cl.relnamespace = con.connamespace AND cl.relfilenode = con.conrelid 
 WHERE con.conrelid = '<table_relid>'::pg_catalog.oid AND con.contype = 'f';

可以找到PostgreSQL系统表的一个很好的资源here。此外,您可以通过查看pg_dump来了解有关内部查询source code收集转储信息的详细信息。

查看pg_dump收集所有数据的最简单方法可能就是使用strace,如下所示:

$ strace -f -e sendto -s8192 -o pg_dump.trace pg_dump -s -n <schema>
$ grep -oP '(SET|SELECT)\s.+(?=\\0)' pg_dump.trace

您仍然需要对语句的混乱进行排序,但是,它应该可以帮助您以编程方式拼凑克隆工具,避免必须转到shell来调用pg_dump

答案 3 :(得分:3)

我将为我的问题分享一个解决方案,只是增加一点点即可。我需要克隆一个架构,创建一个新的数据库用户,并将新架构中所有对象的所有权分配给该用户。

对于下面的示例,我们假设引用架构称为 ref_schema ,目标架构名为 new_schema 。引用架构和其中的所有对象由名为 ref_user 的用户拥有。

1。使用pg_dump转储参考架构:

pg_dump -n ref_schema -f dump.sql database_name

2。创建一个新数据库用户,名称为 new_user

CREATE USER new_user

3。将架构 ref_schema 重命名为 new_schema

ALTER SCHEMA ref_schema RENAME TO new_schema

4。将重命名架构中所有对象的所有权更改为新用户

REASSIGN OWNED BY ref_user TO new_user

5。从转储中恢复原始参考架构

psql -f dump.sql database_name

我希望有人能对此有所帮助。

答案 4 :(得分:0)

碰巧一样。有时我缺少remap_schema :)
问题-上面都没有解决Fc-标准格式,这对于大型架构至关重要。
所以我想出了一些使用它的方法:
下面的伪代码-应该可以使用。
需要在pg_dump的持续时间内重命名源,这当然不是一个选项:(
来源:

pg_dump --pre-data in sql format
psql rename sosurce to target
pg_dump -Fc --data-only
psql rename back
pg_dump --post-data in sql format

目标

sed source_schema->target_schema pre-data sql |psql
pg_restore Fc dump
sed source_schema->target_schema post-data sql |psql
上面的

通常将包括任何其他操作(例如,源和目标之间的用户名不同),但是由于数据将不属于文件的一部分,因此它将更快得多