PostgreSQL에 대해 존재하지 않는 경우 CREATE DATABASE를 시뮬레이션 하시겠습니까?
JDBC를 통해 존재하지 않는 데이터베이스를 만들고 싶습니다. MySQL과 달리 PostgreSQL은 create if not exists
구문을 지원하지 않습니다 . 이를 수행하는 가장 좋은 방법은 무엇입니까?
응용 프로그램은 데이터베이스가 있는지 여부를 알지 못합니다. 데이터베이스가 존재하는지 확인하고 사용해야합니다. 따라서 원하는 데이터베이스에 연결하는 것이 합리적이며 데이터베이스가 존재하지 않아 연결이 실패하면 기본 postgres
데이터베이스 에 연결하여 새 데이터베이스를 만들어야 합니다. Postgres에서 반환 한 오류 코드를 확인했지만 동일한 종류의 관련 코드를 찾을 수 없습니다.
이를 달성하는 또 다른 방법은 postgres
데이터베이스 에 연결 하고 원하는 데이터베이스가 있는지 확인하고 그에 따라 조치를 취하는 것입니다. 두 번째는 운동하기가 조금 지루합니다.
Postgres에서이 기능을 달성하는 방법이 있습니까?
제한
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 문으로 처리합니다.
셸에서 해결 방법
으로 \gexec
만 호출 psql의 필요 번 :
echo "SELECT 'CREATE DATABASE mydb' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'mydb')\gexec" | psql
연결을 위해 더 많은 psql 옵션이 필요할 수 있습니다. 역할, 포트, 비밀번호, ... 참조 :
psql 메타 명령 psql -c "SELECT ...\gexec"
이므로 옵션 은 수동으로 다음과 같은 단일 명령 을 예상 하므로 호출 할 수 없습니다 .\gexec
-c
command
서버에서 완전히 구문 분석 할 수있는 명령 문자열이거나 (즉, psql 특정 기능이 포함되지 않음) 단일 백 슬래시 명령이어야합니다. 따라서-c
옵션 내에서 SQL 및 psql 메타 명령을 혼합 할 수 없습니다 .
Postgres 트랜잭션 내에서 해결 방법
dblink
트랜잭션 블록 외부에서 실행되는 현재 데이터베이스에 대한 연결을 사용할 수 있습니다 . 따라서 효과도 롤백 할 수 없습니다.
이를 위해 추가 모듈 dblink를 설치합니다 (데이터베이스 당 한 번) :
그때:
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에 대한 자세한 설명 :
반복 사용을위한 기능으로 만들 수 있습니다.
another alternative, just in case you want to have a shell script which creates the database if it does not exist and otherwise just keeps it as it is:
psql -U postgres -tc "SELECT 1 FROM pg_database WHERE datname = 'my_db'" | grep -q 1 || psql -U postgres -c "CREATE DATABASE my_db"
I found this to be helpful in devops provisioning scripts, which you might want to run multiple times over the same instance.
I had to use a slightly extended version @Erwin Brandstetter used:
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$
I had to enable the dblink
extension, plus i had to provide the credentials for dblink. Works with Postgres 9.4.
PostgreSQL does not support IF NOT EXISTS
for CREATE DATABASE
statement. It is supported only in CREATE SCHEMA
. Moreover CREATE DATABASE
cannot be issued in transaction therefore it cannot be in DO
block with exception catching.
When CREATE SCHEMA IF NOT EXISTS
is issued and schema already exists then notice (not error) with duplicate object information is raised.
To solve these problems you need to use dblink
extension which opens a new connection to database server and execute query without entering into transaction. You can reuse connection parameters with supplying empty string.
Below is PL/pgSQL
code which fully simulates CREATE DATABASE IF NOT EXISTS
with same behavior like in CREATE SCHEMA IF NOT EXISTS
. It calls CREATE DATABASE
via dblink
, catch duplicate_database
exception (which is issued when database already exists) and converts it into notice with propagating errcode
. String message has appended , skipping
in the same way how it does CREATE SCHEMA IF NOT EXISTS
.
CREATE EXTENSION IF NOT EXISTS dblink;
DO $$
BEGIN
PERFORM dblink_exec('', 'CREATE DATABASE testdb');
EXCEPTION WHEN duplicate_database THEN RAISE NOTICE '%, skipping', SQLERRM USING ERRCODE = SQLSTATE;
END
$$;
This solution is without any race condition like in other answers, where database can be created by external process (or other instance of same script) between checking if database exists and its own creation.
Moreover when CREATE DATABASE
fails with other error than database already exists then this error is propagated as error and not silently discarded. There is only catch for duplicate_database
error. So it really behaves as IF NOT EXISTS
should.
You can put this code into own function, call it directly or from transaction. Just rollback (restore dropped database) would not work.
Testing output (called two times via DO and then directly):
$ sudo -u postgres psql
psql (9.6.12)
Type "help" for help.
postgres=# \set ON_ERROR_STOP on
postgres=# \set VERBOSITY verbose
postgres=#
postgres=# CREATE EXTENSION IF NOT EXISTS dblink;
CREATE EXTENSION
postgres=# DO $$
postgres$# BEGIN
postgres$# PERFORM dblink_exec('', 'CREATE DATABASE testdb');
postgres$# EXCEPTION WHEN duplicate_database THEN RAISE NOTICE '%, skipping', SQLERRM USING ERRCODE = SQLSTATE;
postgres$# END
postgres$# $$;
DO
postgres=#
postgres=# CREATE EXTENSION IF NOT EXISTS dblink;
NOTICE: 42710: extension "dblink" already exists, skipping
LOCATION: CreateExtension, extension.c:1539
CREATE EXTENSION
postgres=# DO $$
postgres$# BEGIN
postgres$# PERFORM dblink_exec('', 'CREATE DATABASE testdb');
postgres$# EXCEPTION WHEN duplicate_database THEN RAISE NOTICE '%, skipping', SQLERRM USING ERRCODE = SQLSTATE;
postgres$# END
postgres$# $$;
NOTICE: 42P04: database "testdb" already exists, skipping
LOCATION: exec_stmt_raise, pl_exec.c:3165
DO
postgres=#
postgres=# CREATE DATABASE testdb;
ERROR: 42P04: database "testdb" already exists
LOCATION: createdb, dbcommands.c:467
If you don't care about the data, you can drop database first and then recreate it:
DROP DATABASE IF EXISTS dbname;
CREATE DATABASE dbname;
Just create the database using createdb
CLI tool:
PGHOST="my.database.domain.com"
PGUSER="postgres"
PGDB="mydb"
createdb -h $PGHOST -p $PGPORT -U $PGUSER $PGDB
If the database exists, it will return an error:
createdb: database creation failed: ERROR: database "mydb" already exists
Upgrade to PostgreSQL 9.5 or greater. If (not) exists was introduced in version 9.5.
참고URL : https://stackoverflow.com/questions/18389124/simulate-create-database-if-not-exists-for-postgresql
'Programing' 카테고리의 다른 글
한 줄에 여러 명령을 실행하는 방법 (0) | 2020.09.11 |
---|---|
유형 선택기와 앰퍼샌드 (&)를 사용하여 부모를 결합하는 Sass (0) | 2020.09.11 |
Typescript 유형 '문자열'은 유형에 할당 할 수 없습니다. (0) | 2020.09.11 |
전문적인 jQuery 기반 Combobox 컨트롤? (0) | 2020.09.11 |
WebClient에서 2 개의 연결 제한을 프로그래밍 방식으로 제거하는 방법 (0) | 2020.09.11 |