Python操作MySQL查询单字段返回字段名而非实际值的问题求解
问题根因
核心错误是SQL语句中给列名错误添加了单引号:
- SQL语法中,单引号的作用是包裹字符串常量,不是包裹列名、表名这类标识符。你写的
SELECT '{field}' FROM ...在传入field值为year时,实际执行的SQL是SELECT 'year' FROM 表名 WHERE ...,数据库不会读取表中year列的存储值,只会固定返回字符串常量'year',因此最终拿到的查询结果是tuple('year',)。 - 你在phpMyAdmin中查询全列正常,是因为
SELECT *语句没有涉及列名的错误引号用法,自然能返回正确数据,和当前报错场景不冲突。
修复方法
基础修复
列名作为SQL标识符,不需要用单引号包裹,去掉字段名两侧的单引号即可拿到列中存储的真实值。
补充:如果列名是SQL保留字、包含空格或特殊字符,需要用MySQL专属的标识符界定符反引号(
)包裹列名,比如`` SELECTyear` FROM 表名 ``,注意反引号和单引号的作用完全不能混淆。
修复单引号错误的核心代码片段:
# 注意:仅修正了引号错误,还存在安全和规范问题见下文 cursor.execute(f"SELECT {field} FROM {NAME_TABLE_SUB_ALU} WHERE idLegajo = '{legajo}' AND idcode = '{code}'")
其他必要优化(结合你提到的重构英文版需求)
- 修正拼写错误:代码中所有
conecction拼写有误,正确拼写为connection,包括方法名__set_conecction_with_data_base、实例属性self.__conecction里的错误拼写,重构英文版时可以统一修正。 - 修复SQL注入风险:当前直接用f字符串拼接所有SQL内容存在严重注入漏洞。其中查询条件的
legajo、code属于值参数,必须用数据库驱动的参数化方式传参;field是列名属于标识符,无法通过参数化传递,必须提前做白名单校验,仅允许传入表中真实存在的合法列名,禁止直接拼接外部传入的任意字符串。 - 完善资源释放逻辑:当前如果SQL执行抛错,游标不会被正常关闭,建议用
with上下文管理器管理连接和游标,保证异常场景下资源也能被正确释放。
修正后的参考代码:
# 提前定义学生-科目表允许查询的列白名单 ALLOWED_FIELDS_SUB_ALU = {"year", "idLegajo", "idcode"} # 补充其他实际存在的业务列 def obtain_field_from_student_subject(self, legajo: str, code: str, field: str) -> tuple: # 先校验传入的字段名是否合法 if field not in ALLOWED_FIELDS_SUB_ALU: raise ValueError(f"非法查询字段: {field}") try: cursor = self.__connection.getcursor() # 列名、表名是校验通过的合法标识符,可安全拼接;值部分用参数化占位符 # 注意不同驱动占位符有区别:pymysql、mysql-connector用%s,sqlite3用?,按实际使用的驱动调整 sql = f"SELECT {field} FROM {NAME_TABLE_SUB_ALU} WHERE idLegajo = %s AND idcode = %s" cursor.execute(sql, (legajo, code)) data = cursor.fetchone() cursor.close() return data except Error as e: raise ValueError(f"\nMySQL错误:查询字段数据失败\n{e}\n")
内容的提问来源于stack exchange,提问作者Facundo Borrás
相关产品推荐
相关产品推荐

