首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如果PostgreSQL不存在,是否模拟创建数据库?

如果PostgreSQL不存在,是否模拟创建数据库?
EN

Stack Overflow用户
提问于 2013-08-23 03:21:09
回答 9查看 169.7K关注 0票数 163

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

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

实现这一点的另一种方法是连接到postgres数据库,并检查所需的数据库是否存在,然后采取相应的操作。第二个问题有点单调乏味。

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

EN

回答 9

Stack Overflow用户

发布于 2016-04-13 15:47:52

另一种选择是,以防你想要一个shell脚本,如果数据库不存在,它会创建数据库,否则就会保持它的原样:

代码语言:javascript
运行
复制
psql -U postgres -tc "SELECT 1 FROM pg_database WHERE datname = 'my_db'" | grep -q 1 || psql -U postgres -c "CREATE DATABASE my_db"

我发现这在devops配置脚本中很有帮助,您可能希望在同一实例上多次运行这些脚本。

对于那些想要解释的人:

代码语言:javascript
运行
复制
-c = run command in database session, command is given in string
-t = skip header and footer
-q = silent mode for grep 
|| = logical OR, if grep fails to find match run the subsequent command
票数 132
EN

Stack Overflow用户

发布于 2019-05-02 18:29:12

PostgreSQL不支持IF NOT EXISTS for CREATE DATABASE语句。仅在CREATE SCHEMA中支持。此外,CREATE DATABASE不能在事务中发出,因此它不能在带有异常捕获的DO块中。

当发出CREATE SCHEMA IF NOT EXISTS并且模式已经存在时,将引发具有重复对象信息的通知(而不是错误)。

要解决这些问题,您需要使用dblink扩展,它打开一个新的数据库服务器连接并执行查询,而无需进入事务。您可以通过提供空字符串来重用连接参数。

下面是PL/pgSQL代码,它完全模拟了CREATE DATABASE IF NOT EXISTS,具有与CREATE SCHEMA IF NOT EXISTS中相同的行为。它通过dblink调用CREATE DATABASE,捕捉duplicate_database异常(当数据库已经存在时发出),并通过传播errcode将其转换为通知。String message以与CREATE SCHEMA IF NOT EXISTS相同的方式附加了, skipping

代码语言:javascript
运行
复制
CREATE EXTENSION IF NOT EXISTS dblink;

DO $$
BEGIN
PERFORM dblink_exec('', 'CREATE DATABASE testdb');
EXCEPTION WHEN duplicate_database THEN RAISE NOTICE '%, skipping', SQLERRM USING ERRCODE = SQLSTATE;
END
$$;

这个解决方案不像在其他答案中那样有任何竞争条件,在检查数据库是否存在和自己创建数据库之间,数据库可以由外部进程(或相同脚本的其他实例)创建。

此外,当CREATE DATABASE由于数据库已存在以外的其他错误而失败时,此错误将作为错误传播,而不是静默丢弃。只有catch for duplicate_database错误。所以它的行为就像IF NOT EXISTS应该做的那样。

您可以将此代码放入自己的函数中,直接调用或从事务中调用。仅回滚(恢复已删除的数据库)将不起作用。

测试输出(通过DO调用两次,然后直接调用):

代码语言:javascript
运行
复制
$ sudo -u postgres psql
psql (9.6.12)
Type "help" for help.

postgres=# \set ON_ERROR_STOP on
postgres=# \set VERBOSITY verbose
postgres=# 
postgres=# CREATE EXTENSION IF NOT EXISTS dblink;
CREATE EXTENSION
postgres=# DO $$
postgres$# BEGIN
postgres$# PERFORM dblink_exec('', 'CREATE DATABASE testdb');
postgres$# EXCEPTION WHEN duplicate_database THEN RAISE NOTICE '%, skipping', SQLERRM USING ERRCODE = SQLSTATE;
postgres$# END
postgres$# $$;
DO
postgres=# 
postgres=# CREATE EXTENSION IF NOT EXISTS dblink;
NOTICE:  42710: extension "dblink" already exists, skipping
LOCATION:  CreateExtension, extension.c:1539
CREATE EXTENSION
postgres=# DO $$
postgres$# BEGIN
postgres$# PERFORM dblink_exec('', 'CREATE DATABASE testdb');
postgres$# EXCEPTION WHEN duplicate_database THEN RAISE NOTICE '%, skipping', SQLERRM USING ERRCODE = SQLSTATE;
postgres$# END
postgres$# $$;
NOTICE:  42P04: database "testdb" already exists, skipping
LOCATION:  exec_stmt_raise, pl_exec.c:3165
DO
postgres=# 
postgres=# CREATE DATABASE testdb;
ERROR:  42P04: database "testdb" already exists
LOCATION:  createdb, dbcommands.c:467
票数 16
EN

Stack Overflow用户

发布于 2016-03-25 19:13:00

我不得不使用一个略微扩展的@Erwin Brandstetter版本:

代码语言:javascript
运行
复制
DO
$do$
DECLARE
  _db TEXT := 'some_db';
  _user TEXT := 'postgres_user';
  _password TEXT := 'password';
BEGIN
  CREATE EXTENSION IF NOT EXISTS dblink; -- enable extension 
  IF EXISTS (SELECT 1 FROM pg_database WHERE datname = _db) THEN
    RAISE NOTICE 'Database already exists';
  ELSE
    PERFORM dblink_connect('host=localhost user=' || _user || ' password=' || _password || ' dbname=' || current_database());
    PERFORM dblink_exec('CREATE DATABASE ' || _db);
  END IF;
END
$do$

我必须启用dblink扩展,另外我还必须提供dblink的凭据。适用于Postgres 9.4。

票数 11
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18389124

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档