重复的postgresql架构,包括序列

ice*_*ker 6 sql postgresql multi-tenant database-schema

我的数据库布局需要为每个新客户创建新架构.目前我使用我在网上找到的内部功能并进行了一些修改.

CREATE FUNCTION copy_schema(
    source_schema character varying, 
    target_schema character varying, 
    copy_data boolean)
RETURNS integer AS
$BODY$
DECLARE
    t_ex integer := 0;
    s_ex integer := 0;
    src_table character varying;
    trg_table character varying;
BEGIN
    if (select 1 from pg_namespace where nspname = source_schema) THEN
        -- we have defined target schema
        s_ex := 1;
    END IF;

    IF (s_ex = 0) THEN
        -- no source schema exist
        RETURN 0;
    END IF;

    if (select 1 from pg_namespace where nspname = target_schema) THEN
        -- we have defined target schema need to sync all table layout
        t_ex := 1;
    ELSE
        EXECUTE 'CREATE SCHEMA '||target_schema||' AUTHORIZATION user';
    END IF;

    FOR src_table IN 
       SELECT table_name 
       FROM information_schema.TABLES 
       WHERE table_schema = source_schema
    LOOP
        trg_table := target_schema||'.'||src_table;
        EXECUTE 
            'CREATE TABLE ' || trg_table || ' (LIKE ' || source_schema || '.' || src_table || ' INCLUDING ALL)';
        IF (copy_data = true) THEN
            EXECUTE 'INSERT INTO ' || trg_table || '(SELECT * FROM ' || source_schema || '.' || src_table || ')';
        END IF;
    END LOOP;

    return t_ex;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
Run Code Online (Sandbox Code Playgroud)

此脚本的问题是新架构中的表继续使用源架构的序列.有没有办法使用sql语句(或其他可靠的方法)来获取新创建的表的序列的新副本(或者甚至是另一种可靠的方法来复制整个模式)?

Erw*_*ter 5

问题的根源

与旧序列的连接来自所涉及列的普通默认值.我在这里引用手册:

只有在INCLUDING DEFAULTS指定时,才会复制复制列定义的默认表达式.默认行为是排除默认表达式,导致新表中复制的列具有null默认值.

由于您使用创建新表

INCLUDING ALL
Run Code Online (Sandbox Code Playgroud)

和:

INCLUDING ALL是一种缩写形式INCLUDING DEFAULTS INCLUDING CONSTRAINTS INCLUDING INDEXES INCLUDING STORAGE INCLUDING COMMENTS.

..你得到相同的默认值.您可以排除默认值,也可以nextval()在创建新表后显式更改默认值.我认为没有任何中间立场.


使用dump/hack转储/恢复更简单

甚至是另一种可靠的复制整个架构的方法

您可以使用以下方式转储模式的架构(相同的单词,不同的含义)pg_dump:

pg_dump $DB -p $PORT -n $SCHEMA -sf /var/lib/postgresql/your_name.pgsql
Run Code Online (Sandbox Code Playgroud)

破解转储(意思是:在其上使用文本编辑器,或编写脚本):交换转储顶部的模式名称,以及SET search_path序列中的所有其他实例以及作为模式资格的可能性.如果您为架构选择了一个唯一的名称,那么使用您喜欢的工具(sedvim或......)进行一次全局搜索和替换就可以完成这项工作.

然后psql针对相同或任何其他数据库运行SQL脚本:

psql $DB -p $PORT -f /var/lib/postgresql/your_name.pgsql > /dev/null
Run Code Online (Sandbox Code Playgroud)

与我最初发布的内容相反,串行列仍然在转储中被拆分(至少在PostgreSQL 9.1.5中).SQL脚本单独创建序列,使用以下命令将它们附加到串行列:

ALTER SEQUENCE seq OWNED BY tbl.col;
Run Code Online (Sandbox Code Playgroud)

并分别设置默认值.

另外:serial当满足所有要求时,当前版本的pgAdmin 在DDL脚本中对工程列进行反向工程.


ice*_*ker 5

所以经过一番思考后,我继续更新我的第一篇文章中提到的sql函数,所以现在它看起来像这样:

CREATE FUNCTION copy_schema(
    source_schema character varying, 
    target_schema character varying, 
    copy_data boolean)
RETURNS integer AS
$BODY$
DECLARE
    t_ex integer := 0;
    s_ex integer := 0;
    src_table character varying;
    trg_table character varying;
BEGIN
    if (select 1 from pg_namespace where nspname = source_schema) THEN
        -- we have defined target schema
        s_ex := 1;
    END IF;

    IF (s_ex = 0) THEN
        -- no source schema exist
        RETURN 0;
    END IF;

    if (select 1 from pg_namespace where nspname = target_schema) THEN
        -- we have defined target schema need to sync all table layout
        t_ex := 1;
    ELSE
        EXECUTE 'CREATE SCHEMA '||target_schema||' AUTHORIZATION user';
    END IF;

    FOR src_table IN 
        SELECT table_name 
        FROM information_schema.TABLES 
        WHERE table_schema = source_schema
    LOOP
        trg_table := target_schema||'.'||src_table;
        EXECUTE 'CREATE TABLE ' || trg_table || ' (LIKE ' || source_schema || '.' || src_table || ' INCLUDING ALL)';
        EXECUTE 'CREATE SEQUENCE ' || trg_table || '_id_seq OWNED BY '||trg_table || '.id';
        EXECUTE 'ALTER TABLE ' || trg_table || ' ALTER COLUMN id SET DEFAULT nextval('''|| trg_table || '_id_seq''::regclass)';
        IF (copy_data = true) THEN
            EXECUTE 'INSERT INTO ' || trg_table || '(SELECT * FROM ' || source_schema || '.' || src_table || ')';
        END IF;
    END LOOP;
    return t_ex;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
Run Code Online (Sandbox Code Playgroud)

对于每个人来说,这不是一个通用的解决方案,但是因为我在架构中的所有表都有名为id的串行字段,所以它适合我.

@ erwin-brandstetter建议使用dump/hack转储文件/恢复转储文件再次返回的版本通常在论坛上看作是要走的路.

在专用服务器的情况下,它可以工作,在共享主机(或需要较少依赖外部脚本)的情况下,内部功能的方式似乎更好.