使用pandas读取DB2数据时Decimal类型异常:数值被放大100倍
解决DB2 Decimal类型读取到Pandas时的格式异常问题
看起来你遇到的问题大概率和挪威本地的区域设置(逗号作为小数分隔符)有关——WinSQL Lite应该是适配了你的系统locale,所以能正确解析显示,但pandas或者DB2驱动在读取时没处理好这个分隔符的差异,导致把100,50(系统locale下的显示格式)当成了整数10050,最终出现小数部分丢失、数值被放大的情况。下面是几个具体的解决步骤:
1. 在DB2连接字符串中指定小数分隔符
不管你用的是ibm_db还是pyodbc连接DB2,都可以在连接参数里明确设置小数分隔符,强制驱动按正确的格式返回数值:
- 如果你用
pyodbc,可以在连接字符串里添加小数分隔符配置:conn_str = ( "DRIVER={IBM DB2 ODBC DRIVER};" "DATABASE=your_db_name;" "HOSTNAME=your_host;" "PORT=your_port;" "UID=your_username;" "PWD=your_password;" "DecimalSeparator=." # 强制用点作为小数分隔符,匹配DB2内部存储格式 ) - 如果你用
ibm_db,可以通过设置连接选项指定小数分隔符:import ibm_db import ibm_db_dbi # 全局设置小数分隔符为点 ibm_db.set_option(None, ibm_db.SQL_ATTR_DECIMAL_SEPARATOR, b'.') # 建立连接 conn = ibm_db_dbi.connect("DATABASE=your_db_name;HOSTNAME=your_host;...", "username", "password")
2. 读取时强制指定列的数据类型
在使用pandas.read_sql()读取数据时,手动指定SAVINGS_AMOUNT列的类型为带精度的decimal,避免pandas自动解析出错:
import pandas as pd from sqlalchemy import create_engine # 假设用SQLAlchemy连接DB2 engine = create_engine("db2+ibm_db://username:password@host:port/db_name") df = pd.read_sql( "SELECT CUSTOMER_ID, FUND_NAME, SAVINGS_AMOUNT FROM SAVINGS_TABLE WHERE CUSTOMER_ID = 1", engine, dtype={"SAVINGS_AMOUNT": "decimal(10,2)"} # 精度要和DB2表中定义的一致 )
3. 调整Pandas的区域设置
如果上面的方法不行,可以强制pandas在解析数值时使用正确的小数分隔符:
import pandas as pd import locale # 设置挪威本地locale locale.setlocale(locale.LC_NUMERIC, 'nb_NO.UTF-8') # 告诉pandas使用当前locale的小数分隔符解析数值 df = pd.read_sql( "SELECT CUSTOMER_ID, FUND_NAME, SAVINGS_AMOUNT FROM SAVINGS_TABLE WHERE CUSTOMER_ID = 1", conn, decimal=',' )
4. 读取后手动修正数值
如果前面的方法都无法生效,可以先把列读取为字符串,再手动转换为数值:
# 先按字符串类型读取目标列 df = pd.read_sql(..., dtype={"SAVINGS_AMOUNT": str}) # 替换逗号为点后转换为数值类型 df['SAVINGS_AMOUNT'] = df['SAVINGS_AMOUNT'].str.replace(',', '.').astype('float') # 或者用locale的atof函数直接解析 df['SAVINGS_AMOUNT'] = df['SAVINGS_AMOUNT'].apply(locale.atof)
优先尝试第一种方法(在连接时指定分隔符),因为这是从根源上解决驱动和系统locale的冲突,效果最稳定。
内容的提问来源于stack exchange,提问作者mortysporty
相关产品推荐
相关产品推荐

