1

我正在尝试accounts_db在 CI(GitLab CI,如果相关)中创建一个 PostgreSQL 数据库,但前提是该数据库尚不存在。由于本机 Postgres 不支持,我目前通过使用 psql 运行 a SELECTon来解决它pg_database,并且只有当它不返回结果时,我才再次使用 psql 运行 a CREATE DATABASE

psql -tc "SELECT 1 FROM pg_database WHERE datname = 'accounts_db';" | grep -q 1 || psql -c "CREATE DATABASE accounts_db;"

这在大多数情况下都有效:accounts_db已经存在,因此grep成功退出并且CREATE DATABASE不执行。

不过,大多数时候并非总是如此。出于某种原因,它有时会出现在 的第二部分||,只是因为数据库已经存在而出错:

$ psql -tc "SELECT 1 FROM pg_database WHERE datname = 'accounts_db';" | grep -q 1 || psql -c "CREATE DATABASE accounts_db;"
ERROR:  database "accounts_db" already exists

这怎么可能?

4

2 回答 2

1

您是否有可能混淆了真实的数据库名称,而真实的数据库名称有时包含混合大小写?

因为

SELECT 1 FROM pg_database WHERE datname = 'MyDB'

将匹配一个名为MyDB但不匹配一个名为的数据库mydb。但是,如果您创建数据库,您将获得一个大小写折叠的名称;例如

CREATE DATABASE MyDB;

创建一个名为mydb. 因此,在这种情况下,您的存在测试将报告没有命名的数据库,MyDB然后您将去创建它,mydb如果它已经存在,则尝试创建并失败。

解决方法是使用标识符引用:

CREATE DATABASE "MyDB";

保存那里的情况。或者,将您对 pg_database 的查询折叠成小写:

SELECT 1 FROM pg_database WHERE datname = lower('MyDB')

...假设您知道您只会尝试以小写形式创建它。

(如果用户决定为您的脚本提供标识符引用的输入,那就更令人兴奋了......)

于 2017-08-16T13:21:20.013 回答
1

顺便说一句:你不需要 grep;您可以使用 psql 的退出代码,只需尝试连接到数据库:(psql 以非零退出值退出的原因更多;但在这种情况下,第二个 psql 也会失败)

#!/bin/sh

THE_NAME="omg_wtf"

psql -U postgres ${THE_NAME} -tc "select 'yes';" || psql -U postgres postgres -tc "CREATE DATABASE ${THE_NAME} ;"

#Eof

但更简单:只需尝试创建数据库,如果失败则退出脚本:


#!/bin/sh

THE_NAME="omg_wtf"

psql -U postgres postgres -tc "CREATE DATABASE ${THE_NAME} ;"|| exit 1

# you wont get here if the above exited
echo "Created ${THE_NAME}"

#Eof
于 2017-08-16T13:02:55.710 回答