我想通过 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
\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/