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

基于Telethon的Telegram机器人SQLite参数化查询问题排查

问题:Telethon机器人数据库查询报错分析与修复

我正在开发一个基于Telethon的Telegram聊天机器人,支持以/search thompson格式根据姓氏查询客户数据库,但在使用参数化查询保障安全时遇到问题。

遇到两类错误:

  • 直接访问query时出现tuple index out of range错误;
  • 使用join方法时出现Incorrect number of bindings supplied. The current statement uses 1, and there are 8 supplied.错误。

完整错误回溯

Traceback (most recent call last):
  File "/Users/.../.../.../.../script.py", line 155, in select
    test_message = create_message_select_query(res)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/.../.../.../.../script.py", line 115, in create_message_select_query
    lname = i[1]
            ~^^^
IndexError: tuple index out of range

相关代码

# 创建匹配结果消息
def create_message_select_query(ans):
    text = ""
    for i in ans:
        id = i[0]
        lname = i[1]
        fname = i[2]
        creation_date = i[3]
        text += "<b>"+ str(id) +"</b> | " + "<b>"+ str(lname) +"</b> | " + "<b>"+ str(fname)+"</b> | " + "<b>"+ str(creation_date)+"</b>\n"
    message = "客户信息查询结果:\n\n"+text
    return message

@client.on(events.NewMessage(pattern="(?i)/search"))
async def select(event):
    try:
        # 获取消息发送者
        sender = await event.get_sender()
        SENDER = sender.id
        
        # 提取/search命令后的查询文本
        list_of_words = event.message.text.split(" ")
        # 获取第一个查询词
        query = list_of_words[1]
             
        sql = "select (SELECT * from customers where lname = ?)"

        # args = ''.join((query))
        args = query
        
        cursor = conn.execute(sql, (args,))
        
        res = cursor.fetchall() # 获取所有查询结果
        
        # 如果有匹配结果,生成消息发送
        if(res):
            test_message = create_message_select_query(res) 
            await client.send_message(SENDER, test_message, parse_mode='html')
        # 无匹配结果时提示
        else:
            text = "未找到匹配的客户"
            await client.send_message(SENDER, text, parse_mode='html')

错误分析与修复方案

1. SQL语句嵌套导致结果格式异常

你的SQL语句用了嵌套查询:select (SELECT * from customers where lname = ?),这种写法会把内部查询的整行结果作为单个字段返回。比如原本customers表的一行是(id, lname, fname, creation_date),现在会变成((id, lname, fname, creation_date),)这样的嵌套元组——外层元组只有1个元素,所以你在create_message_select_query里访问i[1]时必然触发索引越界。

修复:把SQL语句改成正常格式:

sql = "SELECT * from customers where lname = ?"

2. 未处理用户输入不完整的情况

当用户只发送/search而没有输入姓氏时,list_of_words[1]会直接抛出IndexError,你的代码没有做任何边界处理。

修复:添加输入长度检查:

list_of_words = event.message.text.split(" ")
if len(list_of_words) < 2:
    await client.send_message(SENDER, "请输入要查询的姓氏,格式:/search 姓氏", parse_mode='html')
    return
query = list_of_words[1]

3. join方法导致的参数绑定错误

你之前尝试的args = ''.join((query))是错误的:这个写法会把字符串query拆成单个字符的元组(比如"thompson"变成('t','h','o','m','p','s','o','n')),而SQL语句只需要1个参数,因此出现绑定数量不匹配的错误。这个写法完全没必要,直接用query作为参数即可,就像你现在的args = query这样。

4. 保持参数化查询的正确姿势

当前的conn.execute(sql, (args,))是正确的参数化查询写法,能有效防止SQL注入,要继续保持这种方式,不要直接把query拼接到SQL语句中。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 14:15:11