制限
pg_database
同じデータベース クラスタ内の任意のデータベースからアクセスできるシステム カタログを確認できます。トリッキーな部分はCREATE DATABASE
、単一のステートメントとしてしか実行できないことです。マニュアル:
CREATE DATABASE
トランザクション ブロック内では実行できません。
DO
そのため、暗黙的にトランザクション ブロック内にある場合、関数またはステートメント内で直接実行することはできません。Postgres 11 で導入された SQL プロシージャも、これには役立ちません。
psql 内からの回避策
DDL ステートメントを条件付きで実行することにより、psql 内から回避できます。
SELECT 'CREATE DATABASE mydb'
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'mydb')\gexec
マニュアル:
\gexec
現在のクエリ バッファをサーバーに送信し、クエリの出力 (存在する場合) の各行の各列を、実行する SQL ステートメントとして扱います。
シェルからの回避策
psqlを 1 回\gexec
呼び出すだけで済みます。
echo "SELECT 'CREATE DATABASE mydb' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'mydb')\gexec" | psql
接続にはさらに多くの psql オプションが必要になる場合があります。役割、ポート、パスワード、...参照:
is は psql メタコマンドであり、オプションはマニュアルに次のように記載されている単一のコマンドを想定しているpsql -c "SELECT ...\gexec"
ため、同じものを呼び出すことはできません。\gexec
-c
command
サーバーによって完全に解析可能なコマンド文字列 (つまり、psql 固有の機能が含まれていない)、または単一のバックスラッシュ コマンドのいずれかである必要があります。-c
したがって、オプション内で SQL と psql のメタコマンドを混在させることはできません。
Postgre トランザクション内からの回避策
dblink
トランザクション ブロックの外部で実行される現在のデータベースへの接続を使用できます。したがって、効果もロールバックできません。
このための追加モジュール dblink をインストールします (データベースごとに 1 回)。
それで:
DO
$do$
BEGIN
IF EXISTS (SELECT FROM pg_database WHERE datname = 'mydb') THEN
RAISE NOTICE 'Database already exists'; -- optional
ELSE
PERFORM dblink_exec('dbname=' || current_database() -- current db
, 'CREATE DATABASE mydb');
END IF;
END
$do$;
繰り返しになりますが、接続には追加の psql オプションが必要になる場合があります。Ortwin の追加の回答を参照してください。
dblink の詳細な説明:
これを繰り返し使用する機能にすることができます。