PostgreSQL: ejecutando DDL en cada esquema

8

Tengo una configuración de base de datos multiinquilino y necesito agregar algunas columnas. Estoy usando esquemas (y search_path) para particionar a mis usuarios, por lo que estoy buscando una forma ubicua de aplicar un cambio de esquema DDL a todas mis bases de datos. Inicialmente, pensé que podría hacerlo como una sola consulta (cursor en pg_catalog), pero pensar que una invocación de línea de comandos psql -fpodría ser la forma preferida.

Chris
fuente
@RolandoMySQLDBA: en Postgreslugar de PostgreSQLestá perfectamente bien.
a_horse_with_no_name

Respuestas:

11

Preferiría la última solución. Puede recopilar los nombres de esquema en un archivo (un esquema por línea) en psql:

\o change_schema.sql
\t on

SELECT n.nspname
FROM pg_catalog.pg_namespace n
WHERE n.nspname !~ '^pg_' AND n.nspname <> 'information_schema';

-- reset the output
\o
\t off

Entonces puedes hacer fácilmente lo siguiente:

Tener un script de cambio DDL (por ejemplo, change_schema.sql), sin referencia al esquema incluido

SET search_path TO :schema;

BEGIN;
...
...
ALTER TABLE orders
ADD COLUMN last_modified timestamp;
...
...
COMMIT;

Luego puede convertir cada línea de la lista de esquemas en una línea como

psql -h dbhost -d targetdb -f change_schema.sql -v schema=<schema_name>

con un sedcomando simple , por ejemplo, entonces solo tiene que ejecutar estos comandos. Por supuesto, puede convertirlo en un script de shell adecuado si lo desea.

dezso
fuente
1
Así es como lo haría también, aunque usaría el shell para recorrer la lista de esquemas, en lugar de eliminarlo, así que tuve un mejor manejo de errores. Solo para completar, el otro enfoque sería escribirlo como un procedimiento PL / PgSQL que solía EXECUTEejecutar las declaraciones como SQL dinámico.
Craig Ringer
9

Solo para completar, otro enfoque es recorrer todos los esquemas y ejecutar el cambio con SQL dinámico en PL / PgSQL, por ejemplo:

DO
$$
DECLARE
    schemaname name;
BEGIN
   FOR schemaname IN SELECT nspname FROM pg_namespace WHERE nspname NOT LIKE 'pg_%' AND nspname <> 'information_schema' LOOP
       EXECUTE format('ALTER TABLE %I.my_table ADD COLUMN blah blah;', schemaname);
   END LOOP;
END;
$$ LANGUAGE plpgsql;
Craig Ringer
fuente