Ograniczenia
Możesz zapytać o katalog systemowy pg_database
- dostępne z dowolnej bazy danych w tym samym klastrze baz danych. Trudne jest to, że CREATE DATABASE
można wykonać tylko jako pojedynczą instrukcję. Instrukcja:
CREATE DATABASE
nie można wykonać wewnątrz bloku transakcji.
Dlatego nie można go uruchomić bezpośrednio w funkcji lub DO
oświadczenie, gdzie byłby niejawnie wewnątrz bloku transakcji. Procedury SQL, wprowadzone w Postgres 11, również w tym nie mogą pomóc.
Obejście z poziomu psql
Możesz obejść ten problem z poziomu psql, wykonując warunkowe wykonanie instrukcji DDL:
SELECT 'CREATE DATABASE mydb'
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'mydb')\gexec
Instrukcja:
\gexec
Wysyła bieżący bufor zapytania do serwera, a następnie traktuje każdą kolumnę każdego wiersza wyjścia zapytania (jeśli istnieje) jako instrukcję SQL do wykonania.
Obejście z powłoki
Z \gexec
wystarczy zadzwonić do psql raz :
echo "SELECT 'CREATE DATABASE mydb' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'mydb')\gexec" | psql
Możesz potrzebować więcej opcji psql dla swojego połączenia; rola, port, hasło, ... Zobacz:
- Uruchom plik wsadowy za pomocą polecenia psql bez hasła
Tego samego nie można wywołać za pomocą psql -c "SELECT ...\gexec"
od \gexec
to meta-polecenie psql, a -c
opcja oczekuje jednego polecenia dla których instrukcja mówi:
command
musi być albo ciągiem poleceń, który jest całkowicie analizowalny przez serwer (tj. nie zawiera żadnych funkcji specyficznych dla psql), albo pojedynczym poleceniem odwrotnego ukośnika. Dlatego nie można mieszać meta-polecenia SQL i psql w -c
opcja.
Obejście z poziomu transakcji Postgres
Możesz użyć dblink
połączenie z powrotem do bieżącej bazy danych, która działa poza blokiem transakcji. Dlatego też efektów nie można cofnąć.
Zainstaluj w tym celu dodatkowy moduł dblink (raz na bazę danych):
- Jak używać (zainstalować) dblink w PostgreSQL?
Następnie:
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$;
Ponownie, możesz potrzebować więcej opcji psql do połączenia. Zobacz dodaną odpowiedź Ortwina:
- Symulować TWORZENIE BAZY DANYCH, JEŚLI NIE ISTNIEJE dla PostgreSQL?
Szczegółowe wyjaśnienie dla dblink:
- Jak wykonać duże, nieblokujące aktualizacje w PostgreSQL?
Możesz ustawić tę funkcję do wielokrotnego użytku.