使用 MySQL 和 SQLAlchemy ORM 实现高数值精度浮点数

High numerical precision floats with MySQL and the SQLAlchemy ORM

提问人:Christian O'Reilly 提问时间:4/25/2014 更新时间:2/9/2018 访问量:14285

问:

我使用 SQLAlchemy 的 ORM 在 MySQL 中存储一些数字。当我之后获取它们时,它们被截断,因此只有 6 个有效数字被保留,因此我的浮点数失去了很多精度。我想有一种简单的方法可以解决这个问题,但我找不到方法。例如,以下代码:

import sqlalchemy as sa
from sqlalchemy.pool import QueuePool
import sqlalchemy.ext.declarative as sad

Base    = sad.declarative_base()
Session = sa.orm.scoped_session(sa.orm.sessionmaker())

class Test(Base): 
    __tablename__   = "test"
    __table_args__  = {'mysql_engine':'InnoDB'}
    no      = sa.Column(sa.Integer, primary_key=True)
    x       = sa.Column(sa.Float)


a = 43210.123456789
b = 43210.0
print a, b, a - b

dbEngine = sa.create_engine("mysql://chore:BlockWork33!@localhost", poolclass=QueuePool, pool_size=20,  
                                 pool_timeout=180)              
Session.configure(bind=dbEngine)   
session = Session()            

dbEngine.execute("CREATE DATABASE IF NOT EXISTS test")
dbEngine.execute("USE test")  
Base.metadata.create_all(dbEngine)   

try:
    session.add_all([Test(x=a), Test(x=b)])
    session.commit()
except:
    session.rollback()
    raise

[(a,), (b,)] = session.query(Test.x).all()
print a, b, a - b

生产

43210.1234568 43210.0 0.123456788999
43210.1 43210.0 0.0999999999985

我需要一个解决方案来生产它

43210.1234568 43210.0 0.123456788999
43210.1234568 43210.0 0.123456788999
python mysql orm sqlalchemy floating-accuracy

评论

1赞 AMacK 4/25/2014
我不确定,没有使用过sqlalchemy,但根据文档,我认为您应该能够指定sa.types.Float(precision=[precision here])而不是sa。浮。
1赞 Christian O'Reilly 4/25/2014
@AMacK 是的,我知道。我试过了...或者至少我认为我试过了。实际上,我尝试了 sa。Float(Precision=32),完全没有变化。但是,使用 sa.types.Float(precision=32),它确实有效......我想 SQLAlchemy 这个名字中有“炼金术”并非没有道理。如果你把它放在答案(而不是评论)的形式上,我会把它作为官方答案。
0赞 AMacK 4/25/2014
非常感谢。呵呵,奇怪。欢乐时光。

答:

9赞 AMacK 4/25/2014 #1

根据我们在评论中的讨论:而不是允许您指定精度;但是,没有效果。有关详细信息,请参阅文档sa.types.Float(precision=[precision here])sa.Floatsa.Float(Precision=32)

评论

5赞 Marc 4/8/2015
FWIW 我正在为 SQLAlchemy 语法而苦苦挣扎。我的项目在 Flask 中(因此使用 Flask SQLAlchemy)。为了保持一致,这里是对我有用的语法:上面的“3,2”生成了一个 (MySQL) 字段。希望这对那里的某人有所帮助,因为文档有时并不像我想要的那么清晰(Flask 和 SQLAlchemy)。floatColumnName=db.Column(db.Float(precision='3,2')) # db is part of the Flask operationXXX.YY
0赞 Brian Peterson 2/28/2016
你能引用文档吗,或者更具体地说格式没有影响?sa.Float(Precision=32)
0赞 Brian Peterson 2/28/2016
@datamafia或其他任何人,如果您使用 alembic,您是否看到迁移中浮点精度的变化?如果是这样,它是什么样子的?
0赞 Marc 2/29/2016
@BrianPeterson两件事。1-,这是我迁移的副本。2-所有 alembic 迁移都必须用细齿梳进行检查,并且通常是错误的。所以引用的行有效,但我可能不得不从头开始编写它,就像大多数 Alembic 迁移一样。请随时直接与我们联系以获取更多信息。在此示例中,我在MySQL上。sa.Column('ProductPrice', sa.Float(precision='3,2'), nullable=True),
3赞 pnv 4/11/2016
IMO 这是为了 .(5,2)xxx.yy