Python中如何将字符串/字节CSV数据直接写入DuckDB数据库文件?
直接将内存中CSV数据写入DuckDB文件数据库(免临时文件)
问题场景
需要将内存中bytes/字符串形式的CSV数据直接写入DuckDB本地文件数据库,避免生成临时CSV文件中转。现有尝试代码如下:
import io import duckdb data = b'a,b,c\n0,1,2\n3,4,5' rawtbl = duckdb.read_csv( io.BytesIO(data), header=True, sep="," ) con = duckdb.connect('some.db') con.sql('CREATE TABLE foo AS SELECT * FROM rawtbl')
运行后抛出异常:
--------------------------------------------------------------------------- IOException Traceback (most recent call last) Cell In[1], line 10 5 rawtbl = duckdb.read_csv( 6 io.BytesIO(data), header=True, sep="," 7 ) 9 con = duckdb.connect('some.db') ---> 10 con.sql('CREATE TABLE foo AS SELECT * FROM rawtbl') IOException: IO Error: No files found that match the pattern "DUCKDB_INTERNAL_OBJECTSTORE://2843be5a66472f9c"
但直接在内存数据库中执行duckdb.sql('CREATE TABLE foo AS SELECT * FROM rawtbl')是可行的——因为rawtbl属于内存会话的DuckDBPyRelation对象,无法跨会话被文件连接引用。
错误原因
duckdb.read_csv()默认使用内存中的DuckDB会话,而duckdb.connect('some.db')创建的是独立的文件数据库会话,两个会话完全隔离,文件连接无法识别内存会话中的rawtbl对象,因此报错。
解决方案
方法一:在文件连接上下文内读取内存CSV
直接通过文件连接调用read_csv(),生成的关系对象属于该文件会话,可直接用于建表:
import io import duckdb data = b'a,b,c\n0,1,2\n3,4,5' # 建立文件数据库连接 con = duckdb.connect('some.db') # 直接在文件连接中读取内存CSV数据 csv_relation = con.read_csv(io.BytesIO(data), header=True, sep=",") # 创建表 con.sql('CREATE TABLE foo AS SELECT * FROM csv_relation') # 验证结果 print(con.sql('SELECT * FROM foo')) # 关闭连接 con.close()
方法二:注册内存对象后用SQL读取
将内存中的BytesIO对象注册到文件连接中,再通过SQL的read_csv()读取:
import io import duckdb data = b'a,b,c\n0,1,2\n3,4,5' con = duckdb.connect('some.db') # 把内存BytesIO注册为文件连接可识别的对象 con.register('memory_csv', io.BytesIO(data)) # 通过SQL读取注册的对象并创建表 con.sql('CREATE TABLE foo AS SELECT * FROM read_csv(\'memory_csv\', header=True, sep=\',\')') print(con.sql('SELECT * FROM foo')) con.close()
方法三:迁移内存关系到文件数据库
如果已经在内存会话中生成了DuckDBPyRelation,可以通过参数绑定的方式将其导入文件连接:
import io import duckdb data = b'a,b,c\n0,1,2\n3,4,5' # 内存会话中生成关系对象 rawtbl = duckdb.read_csv(io.BytesIO(data), header=True, sep=",") con = duckdb.connect('some.db') # 通过参数绑定将内存关系导入文件数据库并建表 con.execute('CREATE TABLE foo AS SELECT * FROM ?', [rawtbl]) print(con.sql('SELECT * FROM foo')) con.close()
推荐方案
优先选择方法一,所有操作都在文件连接上下文内完成,逻辑最直接,避免跨会话的对象引用问题,性能也最优。
内容的提问来源于stack exchange,提问作者Niko Fohr
相关产品推荐
相关产品推荐

