如何阻止SQLAlchemy或pyodbc反射表时将bigint转为numeric?
问题:SQL Server反射bigint列时出现算术溢出错误
在反射SQL Server数据库表时,某表的id列类型为bigint,初始值为-9223372036854775808,反射过程中触发如下错误:
DataError: (pyodbc.DataError) ('22003', '[22003] [Microsoft][ODBC Driver 18 for SQL Server][SQL Server]Arithmetic overflow error converting bigint to data type numeric. (8115) (SQLExecDirectW)')
明显程序在尝试将bigint转换为numeric时发生溢出,需要阻止该行为或指定转换精度。已尝试两种反射方式均失败:
- 自动反射所有表:
engine = create_engine(db connection) Base = automap_base() Base.prepare(autoload_with=engine)
- 反射指定表:
from sqlalchemy import create_engine, MetaData, Table from sqlalchemy import BigInteger metadata = MetaData() # reflect the table table = Table('OEData', metadata, autoload_with=engine)
使用版本:sqlalchemy 2.0.21、MS Sql server 2014
解决方案
1. 连接字符串添加参数强制bigint不转numeric
ODBC Driver 18默认会将bigint转为numeric类型,可在连接字符串中添加BigIntAsNumeric=No参数,强制驱动以整数类型返回bigint数据,避免溢出:
engine = create_engine( "mssql+pyodbc://user:pass@server/db?driver=ODBC+Driver+18+for+SQL+Server&BigIntAsNumeric=No" )
2. 自定义类型映射覆盖默认转换
通过SQLAlchemy的TypeDecorator自定义类型,强制将SQL Server的bigint映射为SQLAlchemy的BigInteger,避免自动转为numeric:
from sqlalchemy import TypeDecorator, BigInteger, MetaData, Table from sqlalchemy.dialects.mssql import BIGINT class ForceBigInt(TypeDecorator): impl = BigInteger def load_dialect_impl(self, dialect): return dialect.type_descriptor(BIGINT()) # 反射时指定目标列的自定义类型 metadata = MetaData() table = Table( 'OEData', metadata, autoload_with=engine, Column('id', ForceBigInt, primary_key=True) )
3. 手动定义表结构替代自动反射
如果上述方法仍无效,可放弃自动反射,直接手动定义表结构,明确指定id列为BigInteger类型:
from sqlalchemy import Column, BigInteger, MetaData, Table, String metadata = MetaData() OEData = Table( 'OEData', metadata, Column('id', BigInteger, primary_key=True, default=-9223372036854775808), # 其他列按实际表结构补充定义 Column('other_column', String) )
内容的提问来源于stack exchange,提问作者Soha Namnabat
相关产品推荐
相关产品推荐

