2010-03-03 8 views

Respuesta

3
  • Si por esquema de copia quiere decir copia una base de datos, a continuación, sólo tiene que utilizar TEMPLATE opción de crear una copia: CREATE DATABASE dbname_target TEMPLATE dbname_source;

Esto copiará los datos también. Por lo que es posible que desee crear su propia plantilla si necesita muchas copias. Ver Template Databases.

  • Si sólo necesita esquema, entonces le sugiero que ponga sus scripts DB DDL bajo control de origen (que es una buena idea de todos modos) y tienen una secuencia de comandos independiente (con plantilla) que creará el esquema para usted . Básicamente, usted tiene un archivo SQL, donde se sustituye un ${schema_name} con su nuevo nombre de esquema, y ​​luego ejecuta esta secuencia de comandos en la base de datos. De esta manera, si se hace un cambio a esta schema, también puede tener secuencias de comandos para actualizar el esquema para una nueva versión, que tendrá que hacer para cada esquema de usuario en este caso.
+0

Hola tengo una base de datos con múltiples esquemas, mi requisito es, mantuve un esquema como base y deseo crear cada usuario un esquema diferente basado en la estructura del esquema base en la misma base de datos – Giri

+0

ok. luego scripts el esquema de base de datos (ver respuesta editada) – van

5

Utilice pg_dump para volcar su esquema actual en un archivo con formato SQL. Abra el archivo, reemplace schemaname con el nuevo nombre y ejecute este script en su base de datos para crear el nuevo esquema y todos los demás objetos dentro de este esquema.

+3

Tengo una preocupación: si reemplaza 'oldschema' con' newschema' en el archivo sql volcado, no parece haber una manera definitiva de cambiar solo el texto en ese archivo que es refiriéndose al esquema, ¿verdad? Por ejemplo, si tengo un esquema con una palabra común como "hola", ¿se reemplazarán todas las instancias de hello (incluso las instancias relacionadas que no están relacionadas con el esquema)? –

1

Me corrieron algunas pruebas y se encontró el resultado hace referencia al esquema de origen. Así que aquí está mi versión mejorada:

-- 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; 
0

Ésta parece ser la mejor solución que se me ocurrió a.

La idea es utilizar pg_dump con -O (sin dueño) y (OID) -o opciones para conseguir la salida de texto sin formato y sin esquema fuente y la información del propietario.

Dicho de salida i filtro a través sed sustitución de la entrada por defecto

SET search_path = source_schema, pg_catalog; 

con el comando para crear el nuevo esquema y establecer la ruta de búsqueda predeterminado para que

CREATE SCHEMA new_schema; 
SET search_path = new_schema, pg_catalog; 

Después de eso vuelvo a dirigir la transmitir a psql registro para el usuario y la base de datos deseado a qué copia del esquema será transferido.

El último comando para copiar el esquema 'público' al esquema de '2016' en la misma base de datos 'B1' se parece a esto:

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 

Tenga en cuenta que las subvenciones no se transfieren desde el esquema de origen a la nueva uno.

0

Salida this página wiki de PostgreSQL. Contiene una función para clone_schema según lo requiera, pero esta función solo clona tablas. La página se refiere a la publicación this, que contiene una función que clona todo lo que necesita para el esquema.Esta función funcionó bien para mí, logré ejecutarla con la API de JDBC.

Pero tuve algunos problemas cuando los nombres de esquema contenían - o letras mayúsculas. Después de una investigación descubrí que la fuente del problema es el método quote_ident(). Cambio la función clone_schema para que funcione con cualquier nombre de esquema. Comparto la nueva función aquí, espero que ayudar a alguien:

-- 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; 
Cuestiones relacionadas