如何检查Postgres用户是否存在?

113

createuser 可以在 PostgreSQL 中创建一个用户(角色)。有没有一种简单的方法来检查该用户(名称)已经存在?否则, createuser 将返回错误:

createuser: creation of new role failed: ERROR:  role "USR_NAME" already exists

更新:最好可以从shell中执行解决方案,这样更容易在脚本中自动化。

6个回答

190
SELECT 1 FROM pg_roles WHERE rolname='USR_NAME'

在命令行方面(感谢Erwin):

psql postgres -tXAc "SELECT 1 FROM pg_roles WHERE rolname='USR_NAME'"

如果找到了,就返回1,否则什么也不返回。

也就是说:

psql postgres -tXAc "SELECT 1 FROM pg_roles WHERE rolname='USR_NAME'" | grep -q 1 || createuser ...

1
psql 是一个命令。但是如果你在谈论 createuser 命令行实用程序(显然是这样,我一开始没有注意到 create user 中缺少空格),那么忽略退出状态并将输出重定向到 /dev/null 可能更容易些。 - Michael Krelin - hacker
3
你可以在 shell 中(作为 postgres 用户)测试此命令的返回值:psql postgres -tAc "SELECT 1 FROM pg_roles WHERE rolname='USR_NAME'"。如果找到,则返回 1,否则没有其他输出。 - Erwin Brandstetter
1
哈哈,我用了一种更加丑陋的方式来实现:echo "SELECT rolname FROM pg_roles WHERE rolname='USR_NAME';" | psql | grep -c USR_NAME。请将您的解决方案作为答案添加,不要在psql后面加上“postgres”。 - m33lky
2
@m33lky:我只是写了一个评论,因为我认为Michael应该得到这个功劳。他做出了主要贡献。而且他在过去证明自己是一个好运动员。 :)也许Michael想把它纳入他的答案中? - Erwin Brandstetter
1
我建议加入-X标志以防止读取.psqlrc文件。这个文件通常会打开\timing,这很容易与grep -q 1产生误报,因为时间值通常包含1。所以,psql postgres -tXAc ... - jbranchaud
显示剩余5条评论

13

按照与检查数据库是否存在相同的思路

psql -t -c '\du' | cut -d \| -f 1 | grep -qw <user_to_check>

您可以像这样在脚本中使用它:

if psql -t -c '\du' | cut -d \| -f 1 | grep -qw <user_to_check>; then
    # user exists
    # $? is 0
else
    # ruh-roh
    # $? is 1
fi

这将生成比答案https://dev59.com/yWoy5IYBdhLWcg3wcNrh#8546783更大的查询结果。但是,与那个答案不同,这个答案将在重命名为系统表`pg_roles`时保留,但不会在命令`\du`更改时保留。哪一个最有可能不会改变? - Derek Mahar

3

psql -qtA -c "\du USR_NAME" | cut -d "|" -f 1

这段代码使用psql命令查询USR_NAME用户,并通过管道符将结果提取出来进行处理。

[[ -n $(psql -qtA -c "\du ${1}" | cut -d "|" -f 1) ]] && echo "exists" || echo "does not exist"

这段代码用于判断给定的参数是否是一个有效的数据库用户。它使用psql命令查询用户并检查是否存在,如果存在则输出“exists”,否则输出“does not exist”。

2

希望这对于那些可能正在使用python的人有所帮助。
我在GitHubGist上创建了一个完整可行的脚本/解决方案--请参见下面代码片段下方的URL。

# ref: https://dev59.com/yWoy5IYBdhLWcg3wcNrh
check_user_cmd = ("SELECT 1 FROM pg_roles WHERE rolname='%s'" % (deis_app_user))

# our create role/user command and vars
create_user_cmd = ("CREATE ROLE %s WITH LOGIN CREATEDB PASSWORD '%s'" % (deis_app_user, deis_app_passwd))

# ref: https://dev59.com/T5ffa4cB1Zd3GeqP8nxA
class RdsCreds():
    def __init__(self):
        self.conn = psycopg2.connect("dbname=%s user=%s host=%s password=%s" % (admin_db_name, admin_db_user, db_host, admin_db_pass))
        self.conn.set_isolation_level(0)
        self.cur = self.conn.cursor()

    def query(self, query):
        self.cur.execute(query)
        return self.cur.rowcount > 0

    def close(self):
        self.cur.close()
        self.conn.close()

db = RdsCreds()
user_exists = db.query(check_user_cmd)

# PostgreSQL currently has no 'create role if not exists'
# So, we only want to create the role/user if not exists 
if (user_exists) is True:
    print("%s user_exists: %s" % (deis_app_user, user_exists))
    print("Idempotent: No credential modifications required. Exiting...")
    db.close()
else:
    print("%s user_exists: %s" % (deis_app_user, user_exists))
    print("Creating %s user now" % (deis_app_user))
    db.query(create_user_cmd)
    user_exists = db.query(check_user_cmd)
    db.close()
    print("%s user_exists: %s" % (deis_app_user, user_exists))

提供不需要CM模块等的幂等远程(RDS) PostgreSQL创建角色/用户的Python代码。


2

要在单个psql命令中完成此操作:

DO $$BEGIN
IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'USR_NAME')
THEN CREATE ROLE USR_NAME;
END IF;
END$$;

0
受到接受的答案的启发,但不幸的是对我没有起作用(在直接psql调用时出现错误),然后我做了类似于这样的操作:
if ! echo "SELECT * FROM pg_roles WHERE rolname='USR_NAME'" | psql -h localhost -U postgres | grep -E "[1-9][0-9]* rows"; then
  # User not found, create it
  if ! echo "CREATE USER USR_NAME WITH PASSWORD 'USR_NAME' CREATEDB SUPERUSER" | psql -h localhost -U postgres; then
    echo "Error creating USR_NAME"
    exit 1
  fi
fi

即使我认为在这里使用 grep -E "1 rows" 是安全的,因为我们不应该有相同名称的多个用户,但我更喜欢保留 grep -E "[1-9][0-9]* rows",以获得一个通用的“我得到了1个或多个结果”的成功返回。 如果失败,我会放置 exit 1,因为我在一个需要这个用户创建才能正常运行的脚本中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接