Begrænsninger
Du kan spørge systemkataloget pg_database
- tilgængelig fra enhver database i samme databaseklynge. Den vanskelige del er, at CREATE DATABASE
kan kun udføres som en enkelt sætning. Manualen:
CREATE DATABASE
kan ikke udføres i en transaktionsblok.
Så det kan ikke køres direkte inde i en funktion eller DO
erklæring, hvor det ville være inde i en transaktionsblok implicit. SQL-procedurer, introduceret med Postgres 11, kan heller ikke hjælpe med dette.
Løsning fra psql
Du kan omgå det inde fra psql ved at udføre DDL-sætningen betinget:
SELECT 'CREATE DATABASE mydb'
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'mydb')\gexec
Manualen:
\gexec
Sender den aktuelle forespørgselsbuffer til serveren og behandler derefter hver kolonne i hver række af forespørgslens output (hvis nogen) som en SQL-sætning, der skal udføres.
Løsning fra skallen
Med \gexec
du behøver kun at kalde psql én gang :
echo "SELECT 'CREATE DATABASE mydb' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'mydb')\gexec" | psql
Du har muligvis brug for flere psql-indstillinger til din forbindelse; rolle, port, adgangskode, ... Se:
- Kør batchfil med psql-kommando uden adgangskode
Det samme kan ikke kaldes med psql -c "SELECT ...\gexec"
siden \gexec
er en psql-metakommando og -c
option forventer en enkelt kommando for hvilket manualen siger:
command
skal enten være en kommandostreng, der er fuldstændig parserbar af serveren (dvs. den indeholder ingen psql-specifikke funktioner), eller en enkelt backslash-kommando. Du kan således ikke blande SQL- og psql-metakommandoer i en -c
mulighed.
Løsning fra Postgres-transaktionen
Du kan bruge en dblink
forbindelse tilbage til den aktuelle database, som kører uden for transaktionsblokken. Effekter kan derfor heller ikke rulles tilbage.
Installer det ekstra modul dblink til dette (en gang pr. database):
- Hvordan bruger (installerer) dblink i PostgreSQL?
Så:
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$;
Igen kan du få brug for flere psql-indstillinger til forbindelsen. Se Ortwins tilføjede svar:
- Simulerer CREATE DATABASE, HVIS IKKE FINNES for PostgreSQL?
Detaljeret forklaring på dblink:
- Hvordan laver jeg store ikke-blokerende opdateringer i PostgreSQL?
Du kan gøre denne funktion til gentagen brug.