【问题标题】:Pandas Dataframe Inconsistently Pulling Back Oracle Datatypes?Pandas Dataframe 不一致地撤回 Oracle 数据类型?
【发布时间】:2015-12-26 02:37:39
【问题描述】:

我正在尝试使用 Pandas 和 SQLAlchemy 对 Oracle 数据库中的数据进行一些自动分析。但是,Pandas(或 SQLAlchemy,或 cx_Oracle,我不确定是哪个)似乎在读取 Oracle 中定义的数据类型时不一致。

例如,这里是表中的一些列(在 Oracle 中定义):

列名、数据类型

PRINCIPAL_PHOTOGRAPHY_END_DATE  DATE    
PRINCIPAL_PHOTO_START_DATE  DATE
PRODUCER    VARCHAR2(26 BYTE)
RELEASE_AIR_DATE    VARCHAR2(26 BYTE)
RUNNING_TIME_MINUTES    NUMBER(38,0)
RUNNING_TIME_SECONDS    NUMBER(38,0)
EFFECTIVE_TIMESTAMP DATE
EXPIRE_TIMESTAMP    DATE

这是我用来连接并从表中获取信息并将其加载到 pandas 数据帧中的代码:

from sqlalchemy import *
import pandas as pd
orcl_connect_string = 'oracle+cx_oracle://system:oracle@192.168.56.101:1521/?service_name=orcl'
engine = create_engine(orcl_connect_string)
df = pd.read_sql_query('SELECT * FROM INT_PROP', engine)
print df.dtypes

我得到的输出非常令人困惑,因为它并不一致——它在一种情况下捕获了 datetime 数据类型,但在另一种情况下却没有......!?

production_start_date                     object
principal_photography_end_date            object
producer                                  object
release_air_date                          object
running_time_minutes                     float64
running_time_seconds                     float64
effective_timestamp               datetime64[ns]
expire_timestamp                          object

任何想法为什么 Pandas 似乎能够为有效时间戳列读取适当的数据类型,但不能为其他列读取?

编辑(一些版本信息):

  1. 甲骨文 12c
  2. Python 2.7.6
  3. SQLAlchemy 1.0.8
  4. 熊猫 0.16.2

【问题讨论】:

  • 其他列中是否有一些空值或非日期值?无法转换为日期时间(我不知道 oracle 执行类型的能力如何)
  • 其他列可以为空,并且其中确实有一些空条目。但是,我不明白为什么这应该是一个问题——Oracle 确实强制执行数据类型。拥有日期列并不意味着其中的值不能为空——它只是意味着它们不能是非日期。 “NULL”是一个有效的日期,它是一个有效的数字,等等。至少在我使用过的所有关系数据库中。 Pandas 是否反对在非“对象”类型的列中包含空值?
  • pandas 中的一列必须都是相同类型,否则您将获得 dtype 对象...显然 None 是与 datetime 不同的类型:P
  • 在查看了这部分 pandas 文档后,我有点困惑:pandas.pydata.org/pandas-docs/stable/missing_data.html。这似乎表明 pandas 实际上可以使用 NaN 和 NaT 处理这种情况。换句话说,我希望数据框返回数据库中由 NaN 或 NaT 表示的所有 NULL 值(与特定数据类型相关),但数据类型正确分类。
  • 这不是一个不合理的期望,但是我对 pandas 的了解还不够,无法真正为您提供帮助,这就是我刚刚发表评论的原因...

标签: python oracle pandas sqlalchemy cx-oracle


【解决方案1】:
# -*- coding: utf-8 -*-
"""
Description: Autonomous Database Data uploader from different kind files
       Date: Oct 10, 2010
     Python: 3.7
   Packages: cx_Oracle, sqlalchemy, pandas, xlrd
"""
import cx_Oracle
import sqlalchemy
import pandas as pd
import os
import json 
import argparse
import re
import sys


def preCheck():
    """
    Check whether there is user configuration json files and client.
    """

    # Check the existence of TNS_ADMIN
    if os.environ.get('ORACLE_HOME') :
        if os.environ.get('TNS_ADMIN') :
            # Check the existence of the configuration file.
            if not os.path.exists("./.config.json") :
                configADB()
        else:
            print("""
First, download the Autonomous Database Wallet from OCI into the instant client directory.
Secondly, set the environment variable TNS_ADMIN.
Third, modify the sqlnet.ora to contain the correct wallet file path.
Finally, run this program!
                  """)
            exit(-1)
    else:
        print("""
First, download the instant client driver from:
   https://www.oracle.com/database/technologies/instant-client/downloads.html
Secondly, set the environment variable ORACLE_HOME.
Finally, run this program!
          """)
        exit(-1)

def configADB():
    """
    Configure the Autonomous Database Connection
    """
    cfg={}
    cfg['user']=input("Enter your ADB username:")
    cfg['passwd']=input("Enter your ADB user's password:")
    cfg['TNS']=input("Enter your ADB TNS's name:")

    cfgFile=open("./.config.json",'w')
    json.dump(cfg,cfgFile)
    cfgFile.close()

def adbConnect():
    """
    Establish the database connection
    """
    cfgFile=open("./.config.json",'r')
    cfg={}
    cfg=json.load(cfgFile)
    cfgFile.close()

    os.environ['NLS_LANG']="SIMPLIFIED CHINESE_CHINA.UTF8"
    connstr= "oracle+cx_oracle://{}:{}@{}".format(cfg['user'],cfg['passwd'],cfg['TNS'])
    return sqlalchemy.create_engine(connstr, max_identifier_length=128)

def loadCSV(conn, destSchema, destTable, dataType, srcFile):
    """
    Load csv data into ADB
    """
    df=pd.read_csv(srcFile,encoding='utf-8')
    df.to_sql(destTable, conn, schema=destSchema, if_exists='append', index=False, chunksize=10000, dtype=dataType)

def loadJSON(conn, destSchema, destTable, dataType, srcFile):
    """
    Load JSON data into ADB
    """
    df=pd.read_json(srcFile)
    df.to_sql(destTable, conn, schema=destSchema, if_exists='append', index=False, chunksize=10000, dtype=dataType)

def loadExcel(conn, destSchema, destTable, dataType, srcFile):
    """
    Load Excel data into ADB
    """
    df=pd.read_excel(srcFile)
    df.to_sql(destTable, conn, schema=destSchema, if_exists='append', index=False, chunksize=10000, dtype=dataType)


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument("-s", "--schema", help="Autonomous Database's schema")
    parser.add_argument("-t", "--table", help="Schema's table")
    parser.add_argument("-d", "--srcFile", help="Source data file to been loaded")
    args = vars(parser.parse_args())

    if len(sys.argv) == 1:
        parser.print_help()
        exit(-1)

    preCheck()
    adbConn=adbConnect()

    # Generate the dtype
    colType={}
    metadata=sqlalchemy.MetaData(schema=args['schema'])
    tabDef=sqlalchemy.Table(args['table'], metadata, autoload=True, autoload_with=adbConn)
    for col in tabDef.columns:
        colType[col.name]=col.type

    if re.search("\.csv",args['srcFile']) :
        loadCSV(adbConn, args['schema'], args['table'], colType, args['srcFile'])

    if re.search("\.json",args['srcFile']) :
        loadJSON(adbConn, args['schema'], args['table'], colType, args['srcFile'])

    if re.search("\.(xls|xlsx)",args['srcFile']) :
        loadExcel(adbConn, args['schema'], args['table'], colType, args['srcFile'])

    # Close the connection    
    adbConn.dispose()

【讨论】:

    猜你喜欢
    • 2021-12-09
    • 1970-01-01
    • 2019-02-15
    • 1970-01-01
    • 2011-06-28
    • 1970-01-01
    • 2021-04-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多