当我解析ASCII数据文件以将数据导入到表中时,我也遇到了这个问题。问题是,我本能地直观地希望SQLAlchemy在允许唯一数据的同时跳过重复的行。或者由于当前的SQL引擎(如unicode字符串不被允许),随机错误可能会与一行一起抛出。
但是,这种行为超出了SQL接口定义的范围。 SQL API,因此SQLAlchemy只能理解事务和提交,并且不会考虑这种选择性行为。而且,依赖于自动提交功能听起来很危险,因为插入在异常之后停止,而留下其余的数据。
我的解决方案(我不确定它是否最优雅)是处理循环中的每一行,捕获并记录异常,并在最后提交更改。
假设您以某种方式获取列表列表中的数据,即列值列表的行列表。然后你阅读循环中的每一行:
# Python 3.5
from sqlalchemy import Table, create_engine
import logging
# Create the engine
# Create the table
# Parse the data file and save data in `rows`
conn = engine.connect()
trans = conn.begin() # Disables autocommit
exceptions = {}
totalRows = 0
importedRows = 0
ins = table.insert()
for currentRowIdx, cols in enumerate(rows):
try:
conn.execute(ins.values(cols)) # try to insert the column values
importedRows += 1
except Exception as e:
exc_name = type(e).__name__ # save the exception name
if not exc_name in exceptions:
exceptions[exc_name] = []
exceptions[exc_name].append(currentRowIdx)
totalRows += 1
for key, val in exceptions.items():
logging.warning("%d out of %d lines were not imported due to %s."%(len(val), totalRows, key))
logging.info("%d rows were imported."%(importedRows))
trans.commit() # Commit at the very end
conn.close()
为了最大限度地提高此操作的速度,应该禁用自动提交。我在SQLite中使用这些代码,并且它仍然比仅使用sqlite3
的旧版本慢3-5倍,即使禁用了自动提交功能也是如此。 (我移植到SQLAlchemy的原因是为了能够在MySQL中使用它。)
这不是最优雅的解决方案,它不像SQLite的直接接口那么快。如果我简要介绍代码并在不久的将来找到瓶颈,我会用解决方案更新这个答案。