Python 使用df.to_sql()将块写入数据库时出错

Python 使用df.to_sql()将块写入数据库时出错,python,pandas,sqlite,pandas-to-sql,Python,Pandas,Sqlite,Pandas To Sql,现有数据库和预期结果: 我有一个更大的SQLite数据库12gb,表中有4400多万行,我想在Python3中使用Pandas修改这些表 示例目标:我希望将这些大表中的4400万行以块的形式读入DF,操作DF块,并将结果写入新表。如果可能的话,我想替换新表(如果它存在),并将每个块追加到它 因为我的操作只添加或修改列,所以新表的行数应该与原始表的行数相同 问题: 主要问题似乎源于以下代码中的以下行: df.to_sqlnew_表,con=db,如果_存在=append,index=False 当

现有数据库和预期结果:

我有一个更大的SQLite数据库12gb,表中有4400多万行,我想在Python3中使用Pandas修改这些表

示例目标:我希望将这些大表中的4400万行以块的形式读入DF,操作DF块,并将结果写入新表。如果可能的话,我想替换新表(如果它存在),并将每个块追加到它

因为我的操作只添加或修改列,所以新表的行数应该与原始表的行数相同

问题:

主要问题似乎源于以下代码中的以下行:

df.to_sqlnew_表,con=db,如果_存在=append,index=False

当这一行在下面的代码中运行时,我似乎总是得到一个size=N的额外块,加上一个比我预期的要多的观察值。 第一次使用新表名运行此代码时,我收到一个错误: 回溯最近一次呼叫上次: 文件example.py,第23行,在 对于df_发生器中的df: 文件/usr/local/lib/python3.5/site-packages/pandas/io/sql.py,第1420行,在查询迭代器中 data=cursor.fetchmanychunksize sqlite3.0错误:SQL逻辑错误或缺少数据库 如果我使用相同的新表名重新运行脚本,它将针对每个块和一个额外的块+1行运行

当df.to_sql行被注释掉时,循环将按预期的块数运行

完整代码问题的测试示例:

完整代码:example.py

作为pd进口熊猫 导入sqlite3 示例中使用的Helper函数 def REINVAR、outvar、df: df.renamecolumns={invar:outvar},inplace=True 返回DF def计数结果,表: [打印[*]总计:{}表中的{,}行 .formator[0],表 对于c.executeSELECT COUNT*中的r,从{};.formattable]中选择 连接到数据 db=sqlite3.connecttest.db c=db.cursor 新建表格=新建表格 分块加载数据 df_generator=pd.read_sql_queryselect*from test_table limit 10000;,con=db,chunksize=5000 对于df_发生器中的df: 用于修改数据的函数,例如 df=renname,重命名为_name,df printdf.shape df.to_sqlnew_表,con=db,如果_存在=append,index=False 如果创建了新表,则计数 尝试: 计数结果,新表格 除: 通过 一,。结果当 df.to_sqlnew_表,con=db,如果_存在=append,index=False

问题行被注释掉:

$python3 example.py 5000, 22 5000, 22 因为示例代码将我的大表限制为10k行,所以我希望这样

二,。结果当 df.to_sqlnew_表,con=db,如果_存在=append,index=False

a。问题行没有被注释掉

b。这是第一次使用新的_表运行代码:

$python3 example.py 5000, 22 回溯最近一次呼叫上次: 文件example.py,第23行,在 对于df_发生器中的df: 文件/usr/local/lib/python3.5/site-packages/pandas/io/sql.py,第1420行,在查询迭代器中 data=cursor.fetchmanychunksize sqlite3.0错误:SQL逻辑错误或缺少数据库 三,。结果当 df.to_sqlnew_表,con=db,如果_存在=append,index=False

a。问题行没有被注释掉

b。上述代码将在新的_表中再次运行:

$python3 example.py 5000, 22 5000, 22 5000, 22 1, 22 [*]总计:新_表中有20001行 因此,在运行第一次结果2时,我遇到了第一次代码中断的问题,第二次运行第二次结果3时,总行数是我预期的两倍多


如果您对我如何解决此问题提出任何建议,我们将不胜感激。

您可以尝试指定:

db = sqlite3.connect("test.db", isolation_level=None)
#  ---->                        ^^^^^^^^^^^^^^^^^^^^
除此之外,您可以尝试增加chunksize,因为否则提交之间的时间是SQLite DB的一种缩短方式-我想这是导致此错误的原因。。。我还建议使用PostgreSQL、MySQL/MariaDB或类似的工具-它们更可靠,更适合这种数据库大小…

上述解决方案中的时间延迟

@MaxU向数据库连接添加isolation_level=None的解决方案既短又甜。然而,无论出于何种原因,它都会大大降低将每个块写入/提交到数据库的速度。例如,当我在1200万行的表上测试解决方案时,代码花费了6个多小时才完成。相反,从几个文本文件构建原始表需要几分钟的时间

这一洞察导致了一个更快但不那么优雅的解决方案,在一个1200万行的表上完成该解决方案只需不到7分钟,而不是超过6小时。输出行与输入行匹配,解决了我原来问题中的问题

更快但不太优雅的解决方案

由于从文本文件/csv文件构建原始表并使用SQL脚本加载数据,因此我将该方法与Panda的块功能结合起来。基本步骤如下: 低点:

连接到数据库 使用SQL脚本创建一个新表,列和顺序应与您对表所做的任何操作相匹配 把这张庞大的表格分块读 对于每个区块,根据需要修改df,写入csv,使用sql加载csv,并提交更改。 解决方案的主要代码:

作为pd进口熊猫 导入sqlite3 注意:我使用了在build_db.py中编写的函数 在示例解决方案之后显示如下 从构建数据库导入* 示例中使用的Helper函数 def下_varvar,df: s=df[var].str.lower df=df.dropvar,轴=1 df=pd.concat[df,s],轴=1 返回DF 连接到数据 db=sqlite3.connecttest.db c=db.cursor 创建语句 创建\u tablec,创建\u test.sql,path='sql\u clean/' 分块加载数据 df_generator=pd.read_sql_queryselect*来自示例_表;,con=db,chunksize=100000 对于df_发生器中的df: 用于修改数据的函数,例如 df=较低的变量名,df更改列顺序 将df恢复为sql表中的列顺序 db_order=[cmte_id,amndt_ind,rpt_tp,transaction_pgi,image_num,transaction_tp\ 实体、名称、城市、州、邮政编码、雇主、职业、交易、\ 交易金额、其他交易id、交易id、文件编号、备忘cd、备忘文本、子备忘id] df=df[db_顺序] 将区块写入csv file=df_chunk.csv df.to_csvfile,sep='|',header=None,index=False 将区块csv插入数据库 将_文件_插入_tablec,插入_test.sql,文件“|”,path='sql_clean/' db.commit 计数结果 计数结果,测试独立 为上述代码导入了用户函数

build_db.py中的相关函数 def计数结果,表: [打印[*]总计:{}表中的{,}行 .formator[0],表 对于c.executeSELECT COUNT*中的r,从{};.formattable]中选择 def create_tablecursor,sql_脚本,path='sql/': 打印[*]使用{}{}.formatpath、sql\U脚本创建表 qry=打开{}{}.formatpath,sql_脚本'rU'。读取 cursor.executeDescriptory def insert_file_插入_表格光标,sql_脚本,文件,sep=',',path='sql/': 打印[*]将{}插入到带有{}{}.formatfile、path、sql_脚本的表中 qry=打开{}{}.formatpath,sql_脚本'rU'。读取 fileObj=openfile'rU',encoding='latin-1' csvReader=csv.readerfileObj,分隔符=sep,引号= 尝试: 对于csvReader中的行: 尝试: cursor.executeqry,第行 除了sqlite3.IntegrityError作为e: 通过 例外情况除外,如e: 处理文件时打印[*]错误:{},错误代码:{}.formatfile,e 打印[*]sed替换文件{}.formatfile中的空字节 sed_replace_nullfile,clean_null.sh subprocess.callbash clean_null.sh,shell=True 尝试: 打印[*]将{}插入到带有{}{}.formatfile、path、sql_脚本的表中 fileObj=openfile'rU',encoding='latin-1' csvReader=csv.readerfileObj,分隔符=sep,引号= 对于csvReader中的行: 尝试: cursor.executeqry,第行 除了sqlite3.IntegrityError作为e: 通过 版画 例外情况除外,如e: 处理文件时打印[*]错误:{},错误代码:{}.formatfile,e SQL用户脚本

-创建_test.sql 如果存在测试独立,则丢弃表格; 创建表test_indiv cmte_id文本不为空, amndt_ind TEXT, rpt_tp文本, 事务_pgi文本, 图像编号文本, 事务处理文本, 实体文本, 名称文本, 城市文本, 国家文本, 邮政编码文本, 雇主文本, 职业文本, 交易文本, 交易金额文本, 其他id文本, 传输id文本, 文件编号为数字, 备忘录和光盘文本, 备忘录文本, 子单元id数字不为空 ; 在test_indiv sub_id上创建唯一索引idx_test_indiv; -insert_test.sql 插入到测试中 cmte_id, 美国工业部, rpt_tp, 交易记录, 图像_num, 交易记录, 实体, 名称 城市 状态 邮政编码, 雇用者 工作 交易日, 交易金额, 其他身份证, tran_id, 文件编号, 备忘录(光碟), 备忘录文本, 子单元id 价值观 ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ;
在处理大于30 GB的数据时遇到了完全相同的问题。下面是我如何解决这个问题的: 而不是使用read_sql的块特性。我决定创建一个手动块循环器,如下所示:

chunksize=chunk_size
offset=0
for _ in range(0, a_big_number):
    query = "SELECT * FROM the_table %s offset %s" %(chunksize, offset)
    df = pd.read_sql(query, conn)
    if len(df)!=0:
        ....
    else:
        break

是否只想重命名SQLite表中的列?@MaxU否,重命名函数只是一个示例修改。我想跨多个列执行一些复杂的操作,这些操作在Pandas中比SQL更容易执行=None@MaxU,太好了,这是第一次工作,并产生了预期的结果!我确实注意到,尽管最初失败的代码几乎会在瞬间运行
在第二次尝试中,使用您的解决方案,代码几乎有一个延迟,好像每个块都有一个时间。sleep8。有没有办法加快这一速度,或者我应该在计算机内存允许的情况下增加数据块大小?上面的一个警告是,数据块中额外插入的现象实际上没有得到解决,但如果执行的create sql脚本有一条创建唯一索引的语句,则最终表中的行总数是相同的。如果没有唯一索引,则代码有问题。