为什么Sqlalchemy对大数字进行舍入?

时间:2018-06-12 21:49:43

标签: python sqlalchemy oracle12c cx-oracle

Python 3.6.3
Oracle 12c
cx-Oracle 6.3.1

我正在读取平面文件,将它们加载到Pandas数据帧中,并使用to_sql方法将它们插入到Oracle数据库中。我注意到我的ID列长19位,正在四舍五入。例如,如果我尝试插入1234567890123456789,则会将其加载为1234567890123456000。我可以在下面重现这个问题。

from sqlalchemy import create_engine
#from sqlalchemy.dialects import oracle
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, Sequence
from sqlalchemy.orm import sessionmaker
from sqlalchemy.exc import DatabaseError

connection_string = "oracle+cx_oracle://{username}:{password}@my_server.mycollege.edu:1521/?service_name=abc.mycollege.edu"
engine = create_engine(connection_string, echo=True)
Base = declarative_base()

class TestNumber(Base):
    __tablename__ = "test_number"
    id = Column(Integer, Sequence("test_number_id_seq"), primary_key=True)
    #num_one = Column(oracle.NUMBER)
    num_one = Column(Integer)
    num_two = Column(Integer)
    num_three = Column(Integer)

Base.metadata.create_all(engine)

# Inserting num_one like this will cause it to be rounded to 1234567890123460000
sample_one = TestNumber(id=1, num_one=1234567890123456789, num_two=123.3, num_three=34.999)
Session = sessionmaker(bind=engine)
session = Session()
session.add(sample_one)
session.commit()

# Inserting the number here will cause it to be inserted correctly:
engine.execute("INSERT INTO test_number VALUES(2, 1234567890123456789, 11, 12)")

for instance in session.query(TestNumber):
    print(instance.num_one, instance.num_two, instance.num_three)

输出:

2018-06-12 14:25:09,678 INFO sqlalchemy.engine.base.Engine SELECT USER FROM DUAL
2018-06-12 14:25:09,678 INFO sqlalchemy.engine.base.Engine {}
2018-06-12 14:25:09,680 INFO sqlalchemy.engine.base.Engine SELECT CAST('test plain returns' AS VARCHAR(60 CHAR)) AS anon_1 FROM DUAL
2018-06-12 14:25:09,680 INFO sqlalchemy.engine.base.Engine {}
2018-06-12 14:25:09,682 INFO sqlalchemy.engine.base.Engine SELECT CAST('test unicode returns' AS NVARCHAR2(60)) AS anon_1 FROM DUAL
2018-06-12 14:25:09,682 INFO sqlalchemy.engine.base.Engine {}
2018-06-12 14:25:09,685 INFO sqlalchemy.engine.base.Engine SELECT table_name FROM all_tables WHERE table_name = :name AND owner = :schema_name
2018-06-12 14:25:09,685 INFO sqlalchemy.engine.base.Engine {'name': 'TEST_NUMBER', 'schema_name': 'CANVAS_STAGING'}
2018-06-12 14:25:09,687 INFO sqlalchemy.engine.base.Engine SELECT sequence_name FROM all_sequences WHERE sequence_name = :name AND sequence_owner = :schema_name
2018-06-12 14:25:09,687 INFO sqlalchemy.engine.base.Engine {'name': 'TEST_NUMBER_ID_SEQ', 'schema_name': 'CANVAS_STAGING'}
2018-06-12 14:25:09,688 INFO sqlalchemy.engine.base.Engine
CREATE TABLE test_number (
        id INTEGER NOT NULL,
        num_one INTEGER,
        num_two INTEGER,
        num_three INTEGER,
        PRIMARY KEY (id)
)


2018-06-12 14:25:09,689 INFO sqlalchemy.engine.base.Engine {}
2018-06-12 14:25:09,701 INFO sqlalchemy.engine.base.Engine COMMIT
2018-06-12 14:25:09,703 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2018-06-12 14:25:09,704 INFO sqlalchemy.engine.base.Engine INSERT INTO test_number (id, num_one, num_two, num_three) VALUES (:id, :num_one, :num_two, :num_three)
2018-06-12 14:25:09,704 INFO sqlalchemy.engine.base.Engine {'id': 1, 'num_one': 1234567890123456789, 'num_two': 123.3, 'num_three': 34.999}
2018-06-12 14:25:09,710 INFO sqlalchemy.engine.base.Engine COMMIT
2018-06-12 14:25:09,712 INFO sqlalchemy.engine.base.Engine INSERT INTO test_number VALUES(2, 1234567890123456789, 11, 12)
2018-06-12 14:25:09,712 INFO sqlalchemy.engine.base.Engine {}
2018-06-12 14:25:09,713 INFO sqlalchemy.engine.base.Engine COMMIT
2018-06-12 14:25:09,715 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2018-06-12 14:25:09,716 INFO sqlalchemy.engine.base.Engine SELECT test_number.id AS test_number_id, test_number.num_one AS test_number_num_one, test_number.num_two AS test_number_num_two, test_number.num_three AS test_number_num_three
FROM test_number
2018-06-12 14:25:09,716 INFO sqlalchemy.engine.base.Engine {}
1234567890123460000 123 35
1234567890123456789 11 12

这表明如果我使用SQLAlchemy教程中演示的方法,该数字将被舍入,但如果我注入原始SQL语句,它将被正确插入。

这是Sqlalchemy创建的表的DDL:

CREATE TABLE "STAGING"."TEST_NUMBER"
   (    "ID" NUMBER(*,0) NOT NULL ENABLE,
    "NUM_ONE" NUMBER(*,0),
    "NUM_TWO" NUMBER(*,0),
    "NUM_THREE" NUMBER(*,0),
     PRIMARY KEY ("ID")
  USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255
  STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
  PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
  BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
  TABLESPACE "USERS"  ENABLE
   ) SEGMENT CREATION IMMEDIATE
  PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255
 NOCOMPRESS LOGGING
  STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
  PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
  BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
  TABLESPACE "USERS" ;

到目前为止我尝试过:

  • 使用桌面SQL客户端(Dbeaver)创建表并插入数字:这样可以。
  • 在桌面SQL客户端中创建表,但使用SQLalchemy插入值:这仍然是大数字。
  • 尝试使用Sqlalchemy的原生Oracle NUMBER类型:这仍然是大数字。
  • 尝试使用sqlite3进行复制:这不会对大数字进行舍入。

Here's a very similar issue,但它似乎与版本6.0.2中修复的cx_Oracle错误有关。

为什么1234567890123465789四舍五入到1234567890123456000

0 个答案:

没有答案