如何使用EXISTS判断值是否已存在于数据库表(Discord Bot开发场景)
实现方案指导
首先你现有代码存在两个需要修正的问题:
- 存储用户Discord ID的
id字段类型设置错误,BIGSERIAL是数据库自增类型,不适合存储外部固定的用户ID - 直接用
format拼接SQL语句存在SQL注入风险,且未做存在性校验,重复插入同个用户会触发数据库报错
优化步骤
1. 修正建表语句
给存储用户Discord ID的id字段修改为BIGINT类型,同时添加唯一约束,从数据库层面避免重复数据:
cursor.execute("""CREATE TABLE IF NOT EXISTS users ( name VARCHAR(255), id BIGINT NOT NULL UNIQUE, xp INT, id_row SERIAL PRIMARY KEY );""")
2. 集成EXISTS判断实现存在性校验
你可以直接使用带NOT EXISTS判断的参数化插入语句,仅当指定用户ID不存在时才执行插入操作:
if member.id not in bots: cursor.execute(""" INSERT INTO users (name, id, xp) SELECT %s, %s, %s WHERE NOT EXISTS ( SELECT 1 FROM users WHERE id = %s ) """, (str(member), member.id, 0, member.id))
注意:此处使用参数化查询(
%s作为占位符,参数通过元组传入)替代原有的字符串拼接写法,既可以避免SQL注入风险,也不会因为用户名包含特殊字符(如单引号)导致SQL语法错误。
更简洁的替代方案(PostgreSQL专属)
因为你已经给id字段添加了唯一约束,也可以直接使用INSERT ON CONFLICT语法实现相同效果,代码更简洁:
if member.id not in bots: cursor.execute(""" INSERT INTO users (name, id, xp) VALUES (%s, %s, %s) ON CONFLICT (id) DO NOTHING """, (str(member), member.id, 0))
完整修改后代码
@tasks.loop(count=1) async def on_ready(): """The on_ready function is executed when the bot starts up and creates the users table in the database, also adds names, id, number of xp and the server of all to the database participants who are not in the database. """ await bot.wait_until_ready() DiscordComponents(bot) cursor.execute("""CREATE TABLE IF NOT EXISTS users ( name VARCHAR(255), id BIGINT NOT NULL UNIQUE, xp INT, id_row SERIAL PRIMARY KEY );""") for guild in bot.guilds: for member in guild.members: if member.id not in bots: cursor.execute(""" INSERT INTO users (name, id, xp) VALUES (%s, %s, %s) ON CONFLICT (id) DO NOTHING """, (str(member), member.id, 0)) connect.commit() print("Bot connected!")
内容的提问来源于stack exchange,提问作者Hallteon
相关产品推荐
相关产品推荐

