问题:为 PostgreSQL 模拟 CREATE DATABASE IF NOT EXISTS?

我想通过 JDBC 创建一个不存在的数据库。与 MySQL 不同,PostgreSQL 不支持create if not exists语法。实现这一目标的最佳方法是什么?

应用程序不知道数据库是否存在。它应该检查数据库是否存在,应该使用它。所以连接到所需的数据库是有意义的,如果由于数据库不存在而导致连接失败,它应该创建新数据库(通过连接到默认的postgres数据库)。我检查了 Postgres 返回的错误代码,但找不到任何相同的相关代码。

实现此目的的另一种方法是连接到postgres数据库并检查所需的数据库是否存在并采取相应的措施。第二个工作起来有点乏味。

有没有办法在 Postgres 中实现这个功能?

解答

限制

您可以询问系统目录pg_database- 可从同一数据库集群中的任何数据库访问。棘手的部分是CREATE DATABASE只能作为单个语句执行。说明书:

CREATE DATABASE不能在事务块内执行。

所以它不能直接在函数或DO语句中运行,它会隐式地在事务块中运行。随 Postgres 11 引入的 SQL 过程也无法解决这个问题。

psql 内部的解决方法

您可以在 psql 中通过有条件地执行 DDL 语句来解决它:

SELECT 'CREATE DATABASE mydb'
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'mydb')\gexec

说明书:

\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 命令运行批处理文件,无需密码

不能用psql -c "SELECT ...\gexec"调用相同的命令,因为\gexec是一个 psql 元命令,并且-c选项需要一个 command ,手册指出:

command 必须是服务器完全可解析的命令字符串(即,它不包含特定于 psql 的功能),或者是单个反斜杠命令。因此,您不能在-c选项中混合使用 SQL 和 psql 元命令。

Postgres 事务中的解决方法

您可以使用dblink连接回到当前数据库,该数据库在事务块之外运行。因此,效果也不能回滚。

为此安装附加模块 dblink(每个数据库一次):

  • 如何在PostgreSQL中使用(安装)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 选项来进行连接。请参阅 Ortwin 添加的答案:

  • 为 PostgreSQL 模拟 CREATE DATABASE IF NOT EXISTS?

dblink详解:

  • 如何在 PostgreSQL 中进行大的非阻塞更新?

您可以将其设为重复使用的功能。

Logo

PostgreSQL社区为您提供最前沿的新闻资讯和知识内容

更多推荐