to_sql pyodbc count字段不正确或语法错误

Rya*_*yan 8 python sql-server pyodbc pandas

我正在从api网站下载Json数据,并使用sqlalchemy,pyodbc和pandas的to_sql函数将该数据插入到MSSQL服务器中.

我可以下载最多10000行,但是我必须将chunksize限制为10,否则我会收到以下错误:

DBAPIError:(pyodbc.Error)('07002','[07002] [Microsoft] [SQL Server Native Client 11.0] COUNT字段不正确或语法错误(0)(SQLExecDirectW)')[SQL:'INSERT INTO [TEMP_producing_entity_details]

有大约5亿行可供下载,它只是以这种速度爬行.有关解决方法的任何建议吗?

谢谢,

Gor*_*son 14

更新:

pandas 0.23.1已经恢复了0.23.0中引入的问题变化.但是,原始性能的最佳解决方案仍然是CSV - > bcp方法,如下所述.

更新:

大熊猫0.24.0显然已经重新引入了这个问题(参考:这里)


(原始答案)

在pandas版本0.23.0之前,to_sql将为DataTable中的每一行生成一个单独的INSERT:

exec sp_prepexec @p1 output,N'@P1 int,@P2 nvarchar(6)',
    N'INSERT INTO df_to_sql_test (id, txt) VALUES (@P1, @P2)',
    0,N'row000'
exec sp_prepexec @p1 output,N'@P1 int,@P2 nvarchar(6)',
    N'INSERT INTO df_to_sql_test (id, txt) VALUES (@P1, @P2)',
    1,N'row001'
exec sp_prepexec @p1 output,N'@P1 int,@P2 nvarchar(6)',
    N'INSERT INTO df_to_sql_test (id, txt) VALUES (@P1, @P2)',
    2,N'row002'
Run Code Online (Sandbox Code Playgroud)

据推测,为了提高性能,pandas 0.23.0现在生成一个表值构造函数,以便每次调用插入多行

exec sp_prepexec @p1 output,N'@P1 int,@P2 nvarchar(6),@P3 int,@P4 nvarchar(6),@P5 int,@P6 nvarchar(6)',
    N'INSERT INTO df_to_sql_test (id, txt) VALUES (@P1, @P2), (@P3, @P4), (@P5, @P6)',
    0,N'row000',1,N'row001',2,N'row002'
Run Code Online (Sandbox Code Playgroud)

问题是SQL Server存储过程(包括系统存储过程sp_prepexec)仅限于2100个参数,因此如果DataFrame有100列,那么to_sql一次只能插入大约20行.

我们可以计算出所需的chunksize使用量

# df is an existing DataFrame
#
# limit based on sp_prepexec parameter count
tsql_chunksize = 2097 // len(df.columns)
# cap at 1000 (limit for number of rows inserted by table-value constructor)
tsql_chunksize = 1000 if tsql_chunksize > 1000 else tsql_chunksize
#
df.to_sql('tablename', engine, if_exists='replace', index=False, chunksize=tsql_chunksize)
Run Code Online (Sandbox Code Playgroud)

但是,最快的方法仍然可能是:

  • 将DataFrame转储到CSV文件(或类似文件),然后

  • 让Python调用SQL Server bcp实用程序将该文件上载到表中.

  • @user3725021 - 我同意 pandas 更新应该考虑到 T-SQL 限制,至少对于 SQL Server 方言来说是这样。我们可以使用“to_sql”的“chunksize”参数来解决这些问题,但如果 pandas 自己解决这个问题会更好。 (2认同)
  • 我认为他们再次更改了它,并添加了一个默认为“None”的“method”参数,或者换句话说,旧的逐行/“executemany”行为。如果传递“multi”,它将使用多值插入。如果传递一个可调用的,它还可以实现更复杂的处理 - 允许使用例如 Postgresql 的“COPY”。 (2认同)