【问题标题】:How to fix 'generator' object has no attribute 'to_csv' when exporting dataframe导出数据框时如何修复“生成器”对象没有属性“to_csv”
【发布时间】:2019-11-23 07:20:06
【问题描述】:

我正在使用 Python 将数据从 Oracle 表导出到 Pandas DataFrame,然后是 CSV 文件。

但我收到此错误:

AttributeError: 'generator' object has no attribute 'to_csv'

我找不到我的代码问题出在哪里:

import cx_Oracle
import csv
import pandas as pd
import sqlalchemy
from sqlalchemy import create_engine

DATABASE = "MY database"
SCHEMA   = "MY USER"
PASSWORD = "MY PASS"
connstr  = "oracle://{}:{}@{}".format(SCHEMA, PASSWORD, DATABASE)
conn     = sqlalchemy.create_engine(connstr)
result=pd.read_sql('My QUERY' , con=conn, chunksize=10000)
result.to_csv("test",sep=',',chunksize=10000)

【问题讨论】:

  • 您是否检查过它不应该生成的结果类型,正如您的问题所显示的那样
  • 您指定了 chunksize,文档告诉您这会改变返回值类型:如果指定,则返回 一个迭代器,其中 chunksize 是要包含在每个块中的行。

标签: python oracle pandas sqlalchemy export-to-csv


【解决方案1】:

您将获得一个 iterator 数据帧,而不是单个数据帧(生成器是一种迭代器),因为您指定了 chunksize 值。见pandas.read_sql() documentation

chunksize : int,默认无

如果指定,则返回一个迭代器,其中 chunksize 是要包含在每个块中的行数。

你需要遍历那个迭代器;最简单的方法是使用for 循环。然后在写出 CSV 文件时不想再次使用分块。您应该改为以 append 模式打开输出文件,以便将每个块作为新行添加到文件中:

chunks = pd.read_sql('My QUERY', con=conn, chunksize=10000)
for chunk in chunks:  # each chunk is a dataframe
    # append the data from each chunk to the same output file
    chunk.to_csv("test.csv", sep=",", mode="a")

然而,这并不是从表中生成 CSV 文件的有效方法!如果您使用 Oracle SQL*Plus 命令行工具,您将更有效地获取 CSV 文件,请参阅 Oracle 自己的博客文章 Fast Generation of CSV and JSON from Oracle Database

即使只是将 SQLAlchemy 查询直接流式传输到 csv.writer() 对象会更好:

import cx_Oracle
import csv
from sqlalchemy import create_engine

DATABASE  = "MY database"
SCHEMA    = "MY USER"
PASSWORD  = "MY PASS"
BATCHSIZE = 10000
connstr   = "oracle://{}:{}@{}".format(SCHEMA, PASSWORD, DATABASE)
engine   = sqlalchemy.create_engine(connstr, arraysize=BATCHSIZE)
conn     = engine.connect()
with open("test.csv", "w") as outputfile:
    writer = csv.writer(outputfile)
    results = conn.execute('My QUERY')
    writer.writerows(results)

然后cx_Oracle 库会为您将结果从数据库批量流式传输到 Python,然后writer.writerows() 会将这些结果写入您的 CSV 文件。批处理大小由arraysize 参数控制,该参数指示cx_Oracle 库在服务器和客户端之间的每次往返中加载那么多行。如果您必须使用 DataFrames,您可能也想在 Panda 的代码中设置它。

你也不需要 SQLAlchemy,真的;你可以直接在这里使用 cx_Oracle,并设置cursor.arraysize parameter:

import cx_Oracle
import csv

DATABASE  = "MY database"
SCHEMA    = "MY USER"
PASSWORD  = "MY PASS"
BATCHSIZE = 10000

conn      = cx_Oracle.connect(user=SCHEMA, password=PASSWORD, dsn=DATABASE)
cursor    = connection.cursor()
cursor.arraysize = BATCHSIZE

with open("test.csv", "w") as outputfile:
    writer = csv.writer(outputfile)
    results = cursor.execute('My QUERY')
    writer.writerows(results)

【讨论】:

  • 使用 SQL*Plus 而不是 SQL Developer 导出 CSV 可能更高效,请参阅Fast Generation of CSV and JSON from Oracle Database
  • @ChristopherJones 可能,我只是不知道存在 :-) 我看到你也可以调整数组大小和行预取参数!距离我上一次接触 Oracle 工具已经过去了大约五年。
  • @MartijnPieters,非常感谢您的精彩回答。它对我有用。这个建议很棒。我总是需要从 oracle 导出数百万条记录,我真的需要一种有效的方法。
猜你喜欢
  • 2023-03-25
  • 1970-01-01
  • 2020-05-29
  • 2019-05-12
  • 1970-01-01
  • 1970-01-01
  • 2022-06-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多