sql - 为 PostgreSQL 模拟 CREATE DATABASE IF NOT EXISTS?

标签 sql database postgresql jdbc ddl

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

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

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

有什么办法可以在 Postgres 中实现这个功能吗?

最佳答案

限制

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

CREATE DATABASE cannot be executed inside a transaction block.

所以它不能直接在函数内部运行或DO语句,它将隐式地位于事务 block 内。 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

Sends 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.

shell 的解决方法

使用 \gexec 你只需要调用 psql 一次:

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 选项需要一个命令the manual states:

command must 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 -c option.

Postgres 事务中的解决方法

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

为此安装附加模块 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 添加的答案:

dblink详细解释:

您可以将其设为重复使用的函数。

关于sql - 为 PostgreSQL 模拟 CREATE DATABASE IF NOT EXISTS?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18389124/

相关文章:

database - Grails:保存到数据库而不重新加载页面

sql - 如何选择小于时间戳的日期和时间?

java - 第二次访问时为空数据

php - 无法将数据写入数据库

mysql - 如何获取特定值的最大日期和舞台名称?

SQL Server 如何将列值转换为行

mysql - 基于三个关系表连接一个报表

mysql - 如何从 phpMyAdmin 数据库中查找连接字符串?

sql - Azure SQL DB 存在性能问题,100% log/io 的原因是什么?

django - 在本地为 Django 使用 SQLite,在服务器上使用 Postgres