source

PostgreSQL에 대해 데이터베이스 생성 시뮬레이션이 없는 경우

ittop 2023. 6. 1. 22:59
반응형

PostgreSQL에 대해 데이터베이스 생성 시뮬레이션이 없는 경우

JDBC를 통해 존재하지 않는 데이터베이스를 만들고 싶습니다.SQL 달리 Postgre은 SQL을 지원하지 .create if not exists하는 가장 입니까?이를 달성하는 가장 좋은 방법은 무엇입니까?

응용프로그램은 데이터베이스의 존재 여부를 알 수 없습니다.데이터베이스가 존재하는지 확인하고 사용해야 합니다.할 경우 새 (하여).postgres데이터베이스)를 선택합니다.저는 Postgres에서 반환된 오류 코드를 확인했지만 동일한 종류의 관련 코드를 찾을 수 없었습니다.

또 은 이위한또방다연것다입니는결하음에법은를에 하는 것입니다.postgres원하는 데이터베이스가 있는지 확인하고 그에 따라 조치를 취합니다.두 번째는 운동하기에 좀 지루합니다.

Postgres에서 이 기능을 달성할 수 있는 방법이 있습니까?

제한사항

동일한 데이터베이스 클러스터의 모든 데이터베이스에서 액세스할 수 있는 시스템 카탈로그를 요청할 수 있습니다.까다로운 부분은 하나의 문으로만 실행할 수 있다는 것입니다.설명서:

CREATE DATABASE트랜잭션 블록 내에서 실행할 수 없습니다.

따라서 함수나 문 안에서 직접 실행할 수 없으며, 트랜잭션 블록 안에 암묵적으로 있을 수 있습니다. Postgres 11과 함께 도입된 SQL 프로시저도 이를 지원할 수 없습니다.

psql 내에서 해결 방법

조건부로 DDL 문을 실행하면 psql 내에서 해결할 수 있습니다.

SELECT 'CREATE DATABASE mydb'
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'mydb')\gexec

설명서:

\gexec

현재 쿼리 버퍼를 서버로 보낸 다음 쿼리 출력의 각 행(있는 경우)의 각 열을 실행할 SQL 문으로 처리합니다.

셸에서 해결 방법

와 함께\gexecpsql을 한 번만 호출하면 됩니다.

echo "SELECT 'CREATE DATABASE mydb' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'mydb')\gexec" | psql

연결에 더 많은 psql 옵션(역할, 포트, 암호 등)이 필요할 수 있습니다.참조:

와 동일하게 호출할 수 없습니다.psql -c "SELECT ...\gexec" 이래\gexec 및 "psql meta-command"-coption에서는 설명서에 다음과 같은 내용이 포함된 단일 명령을 예상합니다.

command 서버에서 완전히 구문 분석할 수 있는 명령 문자열(즉, psql별 기능이 포함되어 있지 않음) 또는 단일 백슬래시 명령이어야 합니다.따라서 SQL과 psql 메타 명령을 혼합할 수 없습니다.-c선택.

Postgres 트랜잭션 내에서 해결 방법

▁a를 사용할 수 .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에 대한 자세한 설명:

이것을 반복해서 사용할 수 있는 기능으로 만들 수 있습니다.

데이터베이스가 존재하지 않는 경우 데이터베이스를 생성하고 그대로 유지하는 셸 스크립트를 사용하려는 경우 다른 대안:

psql -U postgres -tc "SELECT 1 FROM pg_database WHERE datname = 'my_db'" | grep -q 1 || psql -U postgres -c "CREATE DATABASE my_db"

이는 동일한 인스턴스에서 여러 번 실행할 수 있는 devops 프로비저닝 스크립트에 도움이 됩니다.

설명을 원하는 분들을 위해:

-c = run command in database session, command is given in string
-t = skip header and footer
-q = silent mode for grep 
|| = logical OR, if grep fails to find match run the subsequent command

데이터가 중요하지 않은 경우 먼저 데이터베이스를 삭제한 후 다시 작성할 수 있습니다.

DROP DATABASE IF EXISTS dbname;
CREATE DATABASE dbname;

은 Postgre를 지원하지 .SQL이 지원하지 않음IF NOT EXISTS위해서CREATE DATABASE진술. 에만지다니에서만 됩니다.CREATE SCHEMA.게다가.CREATE DATABASE거래에서 발행할 수 없으므로 다음에 있을 수 없습니다.DO예외 포착 차단

CREATE SCHEMA IF NOT EXISTS가 실행되고 스키마가 이미 존재하며 중복 개체 정보가 있는 알림(오류가 아님)이 발생합니다.

는 이한문해를사합면니다야용해려결하제러를 사용해야 .dblink데이터베이스 서버에 대한 새 연결을 열고 트랜잭션을 시작하지 않고 쿼리를 실행하는 확장입니다.빈 문자열을 제공하는 연결 매개 변수를 재사용할 수 있습니다.

는 아는래입니다.PL/pgSQL를 한 코드CREATE DATABASE IF NOT EXISTS 행동으로CREATE SCHEMA IF NOT EXISTS은 콜트이라고 .CREATE DATABASE경유로dblink, 만나또duplicate_database예외(데이터베이스가 이미 존재할 때 실행됨) 및 이를 전파와 함께 통지로 변환합니다.errcode에 문다자메추가었습니되가 추가되었습니다., skipping 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
$$;

이 솔루션은 다른 답변과 마찬가지로 데이터베이스가 존재하는지 확인하는 것과 자체 작성하는 것 사이의 외부 프로세스(또는 동일한 스크립트의 다른 인스턴스)에 의해 데이터베이스를 작성할 수 있는 경쟁 조건이 없습니다.

게가언제다제 때.CREATE DATABASE데이터베이스가 이미 존재하지 않는 다른 오류와 함께 실패하고 이 오류는 오류로 전파되며 자동으로 삭제되지 않습니다.할 수 있는 것은 오직duplicate_database로 오니다처럼 합니다. 그래서 그것은 정말로 행동합니다.IF NOT EXISTS할까.

이 코드를 직접 또는 트랜잭션에서 호출할 수 있습니다.롤백(삭제된 데이터베이스 복원)만으로는 작동하지 않습니다.

출력 테스트(DO를 통해 두 번 호출된 후 직접 호출):

$ 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

저는 약간 확장된 @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와 함께 작동합니다.

셸을 사용할 수 있다면 시도해 보십시오.

psql -U postgres -c 'select 1' -d $DB &>dev/null || psql -U postgres -tc 'create database $DB'

생각합니다psql -U postgres -c "select 1" -d $DB다쉽습다보다 ▁than가 더 .SELECT 1 FROM pg_database WHERE datname = 'my_db' 되는데, 이 인용구는 , , , 와 하기 쉽습니다.sh -c.

나는 이것을 나의 책임 있는 일에 사용합니다.

- name: create service database
  shell: docker exec postgres sh -c '{ psql -U postgres -tc "SELECT 1" -d {{service_name}} &> /dev/null && echo -n 1; } || { psql -U postgres -c "CREATE DATABASE {{service_name}}"}'
  register: shell_result
  changed_when: "shell_result.stdout != '1'"

가장 좋은 방법은 SQL을 실행하는 것입니다.

CREATE DATABASE MY_DATABASE; 

데이터베이스가 이미 존재하는 경우, 데이터베이스는 "이미 존재하는 오류"를 발생시켜 원하는 작업을 수행할 수 있습니다. 그렇지 않으면 데이터베이스를 작성합니다.사용자의 데이터베이스 위에 새 데이터베이스가 생성될 것이라고 생각하지 않습니다.:D

psql로 실행하는 경우 다른 맛

psql --quiet -d postgres -c "CREATE DATABASE $DB_DATABASE;" || :

이 에도 참고, 이은여출력다니됩이 계속 됩니다.ERROR: database "" already exists무시할 수 있습니다.

포스트그레스 사용자 생성을 위한 If NOT EXIST 옵션이 없기 때문에 끔찍한 해결책인 복잡한 해결책을 모두 읽은 후, 셸 수준에서 간단히 처리할 수 있는 방법이 거의 있다는 것을 잊었습니다.비록 그것이 일부 사람들이 원하는 것은 아닐지라도, 많은 사람들이 절차와 복잡한 구조를 만들지 않고 단순함을 원한다고 생각합니다.

도커를 사용하고 있습니다. 다음은 개발 설정에서 데이터를 로드하는 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"

몇 가지 잘못된 점이 있지만, 제가 원하는 대로 할 수 있는 가장 간단한 방법은 스크립트의 첫 번째 패스에 생성하고, 존재할 때는 두 번째 패스에 계속하는 것입니다.그런데 에코 출력은 표시되지 않지만, 에코 명령이 0으로 종료되기 때문에 명령이 계속됩니다.

db create와 같은 모든 명령에 대해 동일한 작업을 수행할 수 있습니다.이것은 분명히 발생할 수 있는 다른 오류에 대해서도 실패(또는 성공, 관점에 따라)하지만 더 많은 처리를 추가할 수 있도록 psql 출력 프린터를 얻습니다.

한 가지 간편하고 깔끔한 방법을 사용하게 되었습니다.

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

다음과 같은 다른 오류가 예상되는 경우database "x" already exists분명히 작동하지 않습니다(예: 권한 거부).어떤 경우에도 문제가 있는 경우에는 이 시점 이전에 항상 이러한 검사를 수행할 수 있습니다.

다음 값을 설정하는 것을 잊지 마십시오.DATABASE를 전달합니다.createdb지권휘과 같은.가급적이면 다음과 같은 작업도 수행할 수 있습니다.

export PGHOST=localhost
export PGUSER=user
export PGPASSWORD=p455w0rd
...

다음을 사용하여 데이터베이스를 만듭니다.createdbCLI 구:

PGHOST="my.database.domain.com"
PGUSER="postgres"
PGDB="mydb"
createdb -h $PGHOST -p $PGPORT -U $PGUSER $PGDB

데이터베이스가 있으면 다음 오류가 반환됩니다.

createdb: database creation failed: ERROR:  database "mydb" already exists

언급URL : https://stackoverflow.com/questions/18389124/simulate-create-database-if-not-exists-for-postgresql

반응형