使用Pandas read_sql_query指定MySQL decimal(28,5)字段为Decimal类型的技术问询
问题根源
你遇到的TypeError是因为Pandas的dtype参数并不接受Python标准库的decimal.Decimal类作为合法输入——这个参数只识别Pandas/numpy兼容的 dtype 标识(比如字符串别名'Int64'、numpy dtype对象,或者Pandas扩展类型),直接传Decimal类它当然看不懂啦。
不过别担心,有两种方法可以帮你实现明确控制该字段为Decimal类型的需求:
方法1:用converters参数显式转换
read_sql_query自带的converters参数专门用来给指定列设置自定义转换逻辑,刚好可以用来强制把value列转成Decimal:
from decimal import Decimal import pandas as pd # 定义一个转换函数,确保输入值转为Decimal def enforce_decimal(val): return Decimal(val) # 其他列的dtype正常指定 dtypes = { 'id': 'Int64', 'date': 'datetime64' } df = pd.read_sql_query( sql_query, mysql_engine, dtype=dtypes, coerce_float=False, converters={'value': enforce_decimal} # 给value列绑定转换函数 )
这样一来,不管数据库驱动返回什么类型,value列都会被显式转换为decimal.Decimal,完全符合你的控制需求。
方法2:用Pandas Arrow Decimal dtype(适用于Pandas 2.0+)
如果你用的是Pandas 2.0及以上版本,可以直接用官方支持的Arrow Decimal dtype来指定,完美匹配MySQL的decimal(28,5)类型:
import pandas as pd dtypes = { 'id': 'Int64', 'date': 'datetime64', 'value': pd.ArrowDtype('decimal[28,5]') # 对应数据库的decimal(28,5) } df = pd.read_sql_query( sql_query, mysql_engine, dtype=dtypes, coerce_float=False )
注意这个方法需要你先安装pyarrow库(pip install pyarrow)。读取后的value列会是Arrow Decimal类型,和Python标准库的decimal.Decimal完全兼容,要是你需要转为标准Decimal对象,只需要用df['value'].apply(Decimal)就行。
补充:为什么不指定dtype时会自动返回Decimal?
当你不给value列指定dtype时,Pandas会直接沿用数据库驱动(比如mysql-connector-python)返回的类型——这些驱动会自动把MySQL的decimal字段转成Python的decimal.Decimal,Pandas则把它们存在object dtype的列里,所以你能看到单个元素的类型是Decimal。
内容的提问来源于stack exchange,提问作者wawawa

