172

JDBC で存在しないデータベースを作成したい。create if not existsMySQL とは異なり、PostgreSQL は構文をサポートしていません。これを達成するための最良の方法は何ですか?

アプリケーションは、データベースが存在するかどうかを知りません。データベースが存在するかどうかを確認し、それを使用する必要があります。したがって、目的のデータベースに接続することは理にかなっています。データベースが存在しないために接続が失敗した場合は、新しいデータベースを作成する必要があります (既定のpostgresデータベースに接続することによって)。Postgres から返されたエラー コードを確認しましたが、同じ種類の関連コードが見つかりませんでした。

これを実現する別の方法は、データベースに接続してpostgres目的のデータベースが存在するかどうかを確認し、それに応じてアクションを実行することです。2番目のものは、解決するのが少し面倒です。

Postgres でこの機能を実現する方法はありますか?

4

11 に答える 11

168

制限

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 の詳細な説明:

これを繰り返し使用する機能にすることができます。

于 2013-08-22T19:25:39.843 に答える
11

@Erwin Brandstetter が使用したわずかに拡張されたバージョンを使用する必要がありました。

DO
$do$
DECLARE
  _db TEXT := 'some_db';
  _user TEXT := 'postgres_user';
  _password TEXT := 'password';
BEGIN
  CREATE EXTENSION IF NOT EXISTS dblink; -- enable extension 
  IF EXISTS (SELECT 1 FROM pg_database WHERE datname = _db) THEN
    RAISE NOTICE 'Database already exists';
  ELSE
    PERFORM dblink_connect('host=localhost user=' || _user || ' password=' || _password || ' dbname=' || current_database());
    PERFORM dblink_exec('CREATE DATABASE ' || _db);
  END IF;
END
$do$

拡張機能を有効にする必要がありdblink、さらに dblink の資格情報を提供する必要がありました。Postgres 9.4 で動作します。

于 2016-03-25T11:12:59.680 に答える
0

私の意見では、postgresユーザー作成のIF NOT EXISTオプションがないため、ひどい回避策である複雑なソリューションをすべて読んだ後、シェルレベルでそれを処理する簡単な方法があることをほとんど忘れていました。一部の人は望んでいないかもしれませんが、多くの人はシンプルさを求めており、手順や複雑な構造を作成したくないと考えています。

私はdockerを使用しています.devsetupにデータをロードするbashスクリプトからの重要なスニペットは次のとおりです。

execute_psql_command_pipe () {
         $DOCKER_COMMAND exec -it $POSTGRES_CONTAINER bash -c "echo \"$1\"| psql -h localhost -U postgres || echo psql command failed - object likely exists"
}

read -r -d '' CREATE_USER_COMMANDS << EOM
create user User1 WITH PASSWORD 'password';
create user User2 WITH PASSWORD 'password';
EOM

execute_psql_command_pipe "$CREATE_USER_COMMANDS"

それにはいくつかの問題がありますが、それは私が望むことを実行するために見つけることができる最も簡単な方法です: スクリプトの最初のパスで作成し、存在する場合は 2 番目のパスで続行します。ちなみに、echoの出力は表示されませんが、echoコマンドは0で終了するのでコマンドは続きます。

どのコマンドでも同じことができます (db create など)。これは、発生する可能性のある他のエラーに対しても明らかに失敗します (または、パースペクティブによっては成功します) が、psql 出力プリンターを取得するため、より多くの処理を追加できます。

于 2021-06-03T14:12:56.820 に答える
-1

最良の方法は、SQL を実行することです。

CREATE DATABASE MY_DATABASE; 

データベースが既に存在する場合は、「データベースが既に存在するエラー」がスローされます。これは、やりたいことを何でも実行できます。それ以外の場合は、データベースを作成します。あなたのデータベースの上に新しいデータベースが作成されるとは思いません。:D

于 2021-06-28T22:50:17.537 に答える
-2

私が最終的に使用することになった、それを行うための1つの簡単でクリーンな方法:

createdb $DATABASE 2> /dev/null || echo "database already exists"

それ以外のエラーが予想される場合はdatabase "x" already exists、明らかに機能しません (たとえば、許可が拒否されました)。いずれにせよ、それが懸念される場合は、この時点より前にいつでもそのようなチェックを実行できます。

DATABASEの値を設定し、コマンドに必要なスイッチを渡すことを忘れないでくださいcreatedb。できれば、次のようにすることもできます。

export PGHOST=localhost
export PGUSER=user
export PGPASSWORD=p455w0rd
...
于 2021-08-03T21:16:31.567 に答える