Begränsningar
Du kan fråga systemkatalogen pg_database
- tillgänglig från vilken databas som helst i samma databaskluster. Det knepiga är att CREATE DATABASE
kan endast köras som en enskild sats. Manualen:
CREATE DATABASE
kan inte köras i ett transaktionsblock.
Så det kan inte köras direkt i en funktion eller DO
uttalande, där det skulle vara inuti ett transaktionsblock implicit. SQL-procedurer, introducerade med Postgres 11, kan inte heller hjälpa till med detta.
Lösning inifrån psql
Du kan kringgå det inifrån psql genom att köra DDL-satsen villkorligt:
SELECT 'CREATE DATABASE mydb'
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'mydb')\gexec
Manualen:
\gexec
Skickar den aktuella frågebufferten till servern och behandlar sedan varje kolumn i varje rad av frågans utdata (om någon) som en SQL-sats som ska köras.
Lösning från skalet
Med \gexec
du behöver bara anropa psql en gång :
echo "SELECT 'CREATE DATABASE mydb' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'mydb')\gexec" | psql
Du kan behöva fler psql-alternativ för din anslutning; roll, port, lösenord, ... Se:
- Kör batchfil med kommandot psql utan lösenord
Detsamma kan inte anropas med psql -c "SELECT ...\gexec"
sedan \gexec
är ett psql-metakommando och -c
alternativet förväntar sig ett enda kommando för vilken manualen säger:
command
måste antingen vara en kommandosträng som är helt tolkbar av servern (dvs. den innehåller inga psql-specifika funktioner) eller ett enstaka omvänt snedstreck-kommando. Du kan alltså inte blanda SQL- och psql-metakommandon inom en-c
alternativ.
Lösning inifrån Postgres-transaktionen
Du kan använda en dblink
anslutning tillbaka till den aktuella databasen, som körs utanför transaktionsblocket. Effekter kan därför inte heller rullas tillbaka.
Installera tilläggsmodulen dblink för detta (en gång per databas):
- Hur man använder (installerar) dblink i PostgreSQL?
Sedan:
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$;
Återigen kan du behöva fler psql-alternativ för anslutningen. Se Ortwins tillagda svar:
- Simulera SKAPA DATABAS OM INTE FINNS för PostgreSQL?
Detaljerad förklaring för dblink:
- Hur gör jag stora icke-blockerande uppdateringar i PostgreSQL?
Du kan göra detta till en funktion för upprepad användning.