PostgreSQL: exécution de DDL sur chaque schéma

8

J'ai une configuration de base de données multi-locataire et j'ai besoin d'ajouter des colonnes. J'utilise des schémas (et search_path) pour partitionner mes utilisateurs, donc je cherche un moyen omniprésent d'appliquer un changement de schéma DDL à toutes mes bases de données. Au départ, je pensais que je pourrais le faire en tant que requête unique (curseur sur pg_catalog), mais penser à une invocation en ligne de commande de psql -fpourrait être le moyen préféré.

Chris
la source
@RolandoMySQLDBA: Postgresau lieu de PostgreSQLest parfaitement OK.
a_horse_with_no_name

Réponses:

11

Je préférerais cette dernière solution. Vous pouvez collecter les noms de schéma dans un fichier (un schéma par ligne) dans 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

Ensuite, vous pouvez facilement effectuer les opérations suivantes:

Avoir un script changeant DDL (par exemple, change_schema.sql), sans référence au schéma inclus

SET search_path TO :schema;

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

Ensuite, vous pouvez transformer chaque ligne de la liste des schémas en une ligne comme

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

avec une simple sedcommande, par exemple - alors il vous suffit d'exécuter ces commandes. Bien sûr, vous pouvez le transformer en un bon script shell si vous le souhaitez.

dezso
la source
1
Voilà comment je le ferais aussi, bien que j'utiliser le shell boucle sur la liste de schéma, plutôt que sed'ing, donc j'eu une meilleure gestion des erreurs. Juste pour être complet, l'autre approche serait de l'écrire comme une procédure PL / PgSQL qui exécutait EXECUTEles instructions en SQL dynamique.
Craig Ringer
9

Juste pour être complet, une autre approche consiste à boucler sur tous les schémas et à exécuter le changement avec du SQL dynamique en PL / PgSQL, par exemple:

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
la source