PostgreSQL: Menjalankan DDL pada setiap skema

8

Saya memiliki pengaturan DB multi-tenant, dan perlu menambahkan beberapa kolom. Saya menggunakan skema (dan search_path) untuk mempartisi pengguna saya, jadi saya mencari cara di mana-mana untuk menerapkan perubahan skema-DDL ke semua database saya. Awalnya, saya pikir saya mungkin bisa melakukannya sebagai permintaan tunggal (kursor pada pg_catalog), tetapi berpikir doa baris perintah psql -fmungkin cara yang disukai.

Chris
sumber
@RolandoMySQLDBA: Postgresbukannya PostgreSQLtidak apa-apa.
a_horse_with_no_name

Jawaban:

11

Saya lebih suka solusi yang terakhir. Anda dapat mengumpulkan nama skema ke file (satu skema per baris) di 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

Maka Anda dapat dengan mudah melakukan hal berikut:

Miliki skrip pengubah DDL (misalnya, change_schema.sql), tanpa referensi ke skema yang disertakan

SET search_path TO :schema;

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

Kemudian Anda dapat mengubah setiap baris daftar skema menjadi garis seperti

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

dengan sedperintah sederhana , misalnya - maka Anda hanya perlu menjalankan perintah ini. Tentu saja, Anda bisa mengubahnya menjadi skrip shell yang tepat jika Anda mau.

dezso
sumber
1
Ini adalah bagaimana saya melakukannya juga, meskipun saya akan menggunakan shell untuk mengulangi daftar skema, daripada sed'ing, jadi saya lebih baik menangani kesalahan. Hanya untuk kelengkapan, pendekatan lain adalah menuliskannya sebagai prosedur PL / PgSQL yang digunakan EXECUTEuntuk menjalankan pernyataan sebagai SQL dinamis.
Craig Ringer
9

Hanya untuk kelengkapan, pendekatan lain adalah untuk mengulang semua skema dan menjalankan perubahan dengan SQL dinamis dalam PL / PgSQL, misalnya:

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
sumber