You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用SQLite与discord.py开发Discord机器人遇OperationalError求助

问题排查:SQLite OperationalError: no such column 错误解决

我使用SQLite和discord.py开发Discord机器人时,set_ip命令执行报错:OperationalError: no such column: <传入的参数>,代码如下:

@bot.command()
@commands.has_permissions(administrator=True)
async def set_ip(ctx, arg=None):
    if arg == None:
        await ctx.send("You must type the IP address next to the command!")
    elif arg.endswith('.aternos.me') == False:
        await ctx.send('IP must end with .aternos.me')
    elif ctx.guild.id == None:
        await ctx.send("This is a guild-only command!")
    else:
        ipas = None
        id = ctx.guild.id
        conn.execute(f'''DROP TABLE IF EXISTS guild_{id}''')
        conn.execute(f'''CREATE TABLE IF NOT EXISTS guild_{id} (
            ip TEXT NOT NULL
        )''')
        conn.execute(f'''INSERT INTO guild_{id} ("ip") VALUES ({arg})''')
        cursor = conn.execute(f'''SELECT ip FROM guild_{id}''')
        for row in cursor:
            ipas = row[0]
        if ipas == None:
            await ctx.send("Failed to set IP!")
            conn.execute(f'''DROP TABLE IF EXISTS guild_{id}''')
        else:
            await ctx.send(f"Your guild ip is now -> {ipas}")
            print("An ip has been set!")

错误原因

核心问题出在SQL字符串拼接:

conn.execute(f'''INSERT INTO guild_{id} ("ip") VALUES ({arg})''')

当arg是字符串(比如test.aternos.me)时,直接拼接后的SQL语句会变成:

INSERT INTO guild_12345 ("ip") VALUES (test.aternos.me)

SQLite会把test.aternos.me解析为列名(而非字符串值),自然会报错“不存在该列”。

解决方法

改用参数化查询处理字符串参数,同时优化代码逻辑:

修正后的完整代码

@bot.command()
@commands.has_permissions(administrator=True)
async def set_ip(ctx, arg=None):
    # 提前检查是否在服务器内执行
    if not ctx.guild:
        await ctx.send("This is a guild-only command!")
        return
        
    if arg is None:
        await ctx.send("You must type the IP address next to the command!")
        return
        
    if not arg.endswith('.aternos.me'):
        await ctx.send('IP must end with .aternos.me')
        return
        
    guild_id = ctx.guild.id
    # 仅在表不存在时创建,无需每次删除重建
    conn.execute(f'''CREATE TABLE IF NOT EXISTS guild_{guild_id} (
        ip TEXT NOT NULL PRIMARY KEY
    )''')
    # 使用参数化查询插入/替换数据,避免语法错误与SQL注入
    conn.execute(f'''INSERT OR REPLACE INTO guild_{guild_id} (ip) VALUES (?)''', (arg,))
    # 提交事务,确保数据写入数据库
    conn.commit()
    
    # 查询验证结果
    cursor = conn.execute(f'''SELECT ip FROM guild_{guild_id}''')
    ip_row = cursor.fetchone()
    if ip_row:
        ipas = ip_row[0]
        await ctx.send(f"Your guild ip is now -> {ipas}")
        print("An ip has been set!")
    else:
        await ctx.send("Failed to set IP!")
        conn.execute(f'''DROP TABLE IF EXISTS guild_{guild_id}''')
        conn.commit()

关键修改点

  1. 参数化查询:将VALUES ({arg})改为VALUES (?),并将参数放入execute的第二个元组参数中,SQLite会自动处理字符串的引号与转义,彻底避免语法错误。
  2. 新增主键与INSERT OR REPLACE:给ip列添加PRIMARY KEY约束,使用INSERT OR REPLACE实现旧数据覆盖,无需每次删除表重建。
  3. 事务提交:执行插入操作后必须调用conn.commit(),否则数据不会持久化到数据库。
  4. 逻辑前置优化:将服务器环境检查放在最前面,减少无效代码执行。
  5. 简化查询:用cursor.fetchone()直接获取单行结果,替代循环遍历。

内容的提问来源于stack exchange,提问作者kagent263

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 20:25:22