限制
您可以询问系统目录pg_database
——可从同一数据库群集中的任何数据库访问.棘手的是CREATE DATABASE
只能作为一条语句执行.The manual:
CREATE DATABASE
不能在事务块内执行.
因此,它不能直接在函数或DO
语句中运行,因为它会隐式地在事务块中运行.SQL程序,与Postgres 11、cannot help with this either一起引入.
psql内部的解决方法
您可以通过有条件地执行DDL语句,在psql中解决这个问题:
SELECT 'CREATE DATABASE mydb'
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'mydb')\gexec
The manual:
\gexec
将当前查询缓冲区发送到服务器,然后将查询输出的每一行(如果有)的每一列视为要执行的SQL语句.
shell 的变通方法
有了\gexec
,你只需要调用psql once:
echo "SELECT 'CREATE DATABASE mydb' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'mydb')\gexec" | psql
你的连接可能需要更多的psql选项;角色、端口、密码...见:
psql -c "SELECT ...\gexec"
不能调用同样的命令,因为\gexec
是一个psql元命令,-c
选项需要一个command,其中the manual states:
102必须是完全可由服务器解析的命令字符串(即,它不包含特定于psql的功能),或者是单个反斜杠命令.因此,不能在-c
选项中混合使用SQL和psql元命令.
Postgres交易中的解决方案
您可以使用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选项.见奥特温补充的答案:
dblink的详细说明:
您可以将其作为一个函数重复使用.