小编典典

为 PostgreSQL 模拟 CREATE DATABASE IF NOT EXISTS?

all

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

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

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

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


阅读 191

收藏
2022-07-28

共1个答案

小编典典

限制

您可以询问系统目录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 语句。

从外壳解决方法

\gexec你只需要调用psql 一次

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

psql -c "SELECT ...\gexec"由于\gexec是 psql
元命令,因此不能调用相同的命令,并且该选项需要手动声明-c的单个 命令:

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

Postgres 事务中的解决方法

您可以使用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$;
2022-07-28