Restrictions
You can ask the system catalog pg_database - accessible from any database in the same database cluster. The tricky part is that CREATE DATABASE can only be executed as a single statement. The manual:
CREATE DATABASEcannot be executed inside a transaction block.
So it cannot be run directly inside a function or DO statement, where it would be inside a transaction block implicitly. SQL procedures, introduced with Postgres 11, cannot help with this either.
Workaround from within psql
You can work around it from within psql by executing the DDL statement conditionally:
SELECT 'CREATE DATABASE mydb'
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'mydb')\gexec
The manual:
\gexecSends the current query buffer to the server, then treats each column of each row of the query's output (if any) as a SQL statement to be executed.
Workaround from the shell
With \gexec you only need to call psql once:
echo "SELECT 'CREATE DATABASE mydb' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'mydb')\gexec" | psql
You may need more psql options for your connection; role, port, password, ... See:
- Run batch file with psql command without password
The same cannot be called with psql -c "SELECT ...\gexec" since \gexec is a psql meta‑command and the -c option expects a single command for which the manual states:
commandmust be either a command string that is completely parsable by the server (i.e., it contains no psql-specific features), or a single backslash command. Thus you cannot mix SQL and psql meta-commands within a-coption.
Workaround from within Postgres transaction
You could use a dblink connection back to the current database, which runs outside of the transaction block. Effects can therefore also not be rolled back.
Install the additional module dblink for this (once per database):
- How to use (install) dblink in PostgreSQL?
Then:
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
;
Again, you may need more psql options for the connection. See Ortwin's added answer:
- Simulate CREATE DATABASE IF NOT EXISTS for PostgreSQL?
Detailed explanation for dblink:
- How do I do large non-blocking updates in PostgreSQL?
You can make this a function for repeated use.
Answer from Erwin Brandstetter on Stack OverflowRestrictions
You can ask the system catalog pg_database - accessible from any database in the same database cluster. The tricky part is that CREATE DATABASE can only be executed as a single statement. The manual:
CREATE DATABASEcannot be executed inside a transaction block.
So it cannot be run directly inside a function or DO statement, where it would be inside a transaction block implicitly. SQL procedures, introduced with Postgres 11, cannot help with this either.
Workaround from within psql
You can work around it from within psql by executing the DDL statement conditionally:
SELECT 'CREATE DATABASE mydb'
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'mydb')\gexec
The manual:
\gexecSends the current query buffer to the server, then treats each column of each row of the query's output (if any) as a SQL statement to be executed.
Workaround from the shell
With \gexec you only need to call psql once:
echo "SELECT 'CREATE DATABASE mydb' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'mydb')\gexec" | psql
You may need more psql options for your connection; role, port, password, ... See:
- Run batch file with psql command without password
The same cannot be called with psql -c "SELECT ...\gexec" since \gexec is a psql meta‑command and the -c option expects a single command for which the manual states:
commandmust be either a command string that is completely parsable by the server (i.e., it contains no psql-specific features), or a single backslash command. Thus you cannot mix SQL and psql meta-commands within a-coption.
Workaround from within Postgres transaction
You could use a dblink connection back to the current database, which runs outside of the transaction block. Effects can therefore also not be rolled back.
Install the additional module dblink for this (once per database):
- How to use (install) dblink in PostgreSQL?
Then:
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
;
Again, you may need more psql options for the connection. See Ortwin's added answer:
- Simulate CREATE DATABASE IF NOT EXISTS for PostgreSQL?
Detailed explanation for dblink:
- How do I do large non-blocking updates in PostgreSQL?
You can make this a function for repeated use.
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.
For those of you who would like an explanation:
-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
mysql - DROP DATABASE IF EXISTS CREATE DATABASE IF NOT EXISTS USE in PostgreSQL - Database Administrators Stack Exchange
In PostgreSQL, I want to check for the existence of a database and user and perform a branch process
Can I create a new database when it does not exist by sqlalchemy?
Postgres 9.3 feature highlight: IF EXISTS and IF NOT EXISTS
Videos
There are two different ways of creating a database in PostgreSQL. One is from the command line. The other is from the PostgreSQL console.
Command Line
In order to be able to create a database from the command line, you must first change to a user with rights to create a database. As you have shown with the \du command above, the user with those rights is postgres.
root@eric-desktop:/home/eric# su postgres
postgres@eric-desktop:/home/eric$ createdb prismatest2
postgres@eric-desktop:/home/eric$
As you can see, the creatdb command does not give any feedback. You need to confirm the creation by listing the current databases:
psql -U postgres -l
List of databases
Name | Owner | Encoding | Collate | Ctype | ICU Locale | Locale Provider | Access privileges
-------------+----------+----------+-------------+-------------+------------+-----------------+-----------------------
postgres | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc |
prismatest | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc |
prismatest2 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc |
PostgreSQL Console
Another possibility is to use the PostgreSQL console. To enter the console:
root@eric-desktop:/home/eric# sudo -u postgres psql psql (15.7 (Debian 15.7-0+deb12u1)) Type "help" for help.
postgres=#
postgres=# CREATE DATABASE "prismatest3";
CREATE DATABASE
postgres=#
To confirm the creation of the database, list the databases:
postgres=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | ICU Locale | Locale Provider | Access privileges
-------------+----------+----------+-------------+-------------+------------+-----------------+-----------------------
postgres | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc |
prismatest | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc |
prismatest2 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc |
prismatest3 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc |
Notice how the prompt has changed from the first line to the second:
v
postgres=# createdb prismatest
postgres-# \l
^
psql is hinting that you are entering more lines of the same command.
Enter the semicolon (";") that terminates the create database statement.
postgres=# createdb prismatest ;