MySQL中SUM(BIGINT)作为预处理语句执行时返回bytearray而非BIGINT
我帮你搞定这个头疼的类型映射问题!你遇到的情况是MySQL Connector/Python在预处理语句模式下,对BIGINT字段的SUM结果类型处理和普通字符串插值不一致导致的——驱动在预处理模式下可能把超出特定范围的数值以bytearray形式返回,而非预期的Decimal或整数。下面给你几个靠谱的解决方案:
方案1:显式转换SUM结果为DECIMAL(最稳妥)
直接在SQL查询里把SUM的结果用CAST转换成DECIMAL类型,强制驱动识别为数值类型,这样不管是预处理还是普通执行都能返回Decimal:
# 修改后的查询语句 query_sql = """ SELECT COUNT(billable_size), CAST(SUM(billable_size) AS DECIMAL(20, 0)) AS total_billable, MIN(billable_size), MAX(billable_size) FROM inv_files WHERE billable_size >= %s AND billable_size < %s """ # 预处理方式执行(注意用参数元组,避免SQL注入!) cursor = cnx.cursor() cursor.execute(query_sql, (from_size, to_size)) count, total, min_size, max_size = cursor.fetchone() # 此时total就是Decimal类型,和字符串插值的结果一致
这里DECIMAL(20,0)的精度足够覆盖你提到的1e+14的最大值(20位足够容纳100万亿以内的数值)。
方案2:启用纯Python驱动模式
MySQL Connector/Python有两种驱动模式:C扩展模式和纯Python模式。C扩展模式可能在类型映射上有特殊处理,换成纯Python模式可以解决这个问题,只需在建立连接时添加use_pure=True参数:
# 建立连接时启用纯Python模式 cnx = mysql.connector.connect( user="your_username", password="your_password", host="your_host", database="your_db", use_pure=True # 关键参数 ) # 原来的查询语句不用改 query_sql = """ SELECT COUNT(billable_size), SUM(billable_size), MIN(billable_size), MAX(billable_size) FROM inv_files WHERE billable_size >= %s AND billable_size < %s """ cursor = cnx.cursor() cursor.execute(query_sql, (from_size, to_size)) result = cursor.fetchone() # 此时SUM的结果会是Decimal类型
这个方案不需要修改SQL,但注意纯Python模式的性能可能比C扩展模式稍差一点,不过对于统计类查询影响不大。
方案3:手动转换bytearray为数值(兜底方案)
如果暂时不能修改SQL或连接配置,可以在获取结果后手动把bytearray转成Decimal或整数:
cursor.execute(query_sql, (from_size, to_size)) result = cursor.fetchone() # 把bytearray转成整数,再转成Decimal(适配大数值) sum_value = Decimal(int.from_bytes(result[1], byteorder='big'))
注意这里的字节序要和MySQL返回的一致,一般是大端(byteorder='big'),如果转换后数值不对,可以试试byteorder='little'。
另外提醒一下:你之前用的字符串插值方式虽然返回类型正确,但存在SQL注入风险,预处理语句才是安全的做法,建议始终使用cursor.execute(query, params)的方式执行查询。
内容的提问来源于stack exchange,提问作者David Moles

