TOU sql pyodbc计数字段不正确或语法错误

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

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

DBAPIError:(pyodbc.Error)(’07002’,'[07002][Microsoft][SQL Server
本机客户端11.0]计数字段不正确或语法错误(0)
(SQLExecDirectW)][SQL:’插入[TEMP\u producting\u entity\u details]

大约有5亿行需要下载,它只是以这样的速度爬行。有什么建议吗

谢谢

在提出这个问题时,pandas 0.23.0刚刚发布。该版本将的默认行为更改为_sql(),从调用DBAPI.executemany()方法改为构造表值构造函数(TVC),通过使用单个.execute()插入多行来提高上传速度调用INSERT语句。不幸的是,这种方法经常超过T-SQL对存储过程2100个参数值的限制,导致问题中引用的错误

此后不久,pandas的后续版本将方法=参数添加到.to_sql()。默认的–方法=None–恢复了以前使用.executemany()的行为,同时指定方法="multi"将告诉.to_sql()使用较新的TVC方法

大约在同一时间,SQLAlchemy 1.3发布了,它为create\u engine()添加了fast\u executemany=True参数使用Microsoft针对SQL Server的ODBC驱动程序大大提高了上传速度。通过这一增强,method=None证明至少与method="multi"一样快,同时避免了2100参数限制

因此,对于pandas、SQLAlchemy和pyodbc的当前版本,将.to_sql()与Microsoft的sql Server ODBC驱动程序一起使用的最佳方法是使用fast\u executemany=Trueto_sql()的默认行为,即

连接\u uri=(
&mssql+pyodbc://scott:tiger^[email protected]/db_name"
&“driver=ODBC+driver+17+for+SQL+Server”;
)
引擎=创建引擎(连接uri,fast\U executemany=True)
df.to“U sql”(“table”u name,“引擎”,index=False,如果“U exists=”append“)

这是在Windows、macOS和Linux变体上运行的应用程序的推荐方法,Microsoft为其ODBC驱动程序支持这些应用程序。如果需要使用FreeTDS ODBC,则可以使用方法=chunksize=调用到sql()


(原始答案)

在pandas版本0.23.0之前,to_sql将为数据表中的每一行生成单独的插入:

exec [email protected] output,N'@p1 int,@P2 nvarchar(6),
N'插入df_至_sql_测试(id,txt)值(@P1,@P2)',
0,N'row000'
执行[email protected]输出,N'@p1 int,@P2 nvarchar(6)',
N'插入df_至_sql_测试(id,txt)值(@P1,@P2)',
1,N'row001'
执行[email protected]输出,N'@p1 int,@P2 nvarchar(6)',
N'插入df_至_sql_测试(id,txt)值(@P1,@P2)',
2,N'row002'

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

exec [email protected] output,N'@p1 int,@P2 nvarchar(6),@P3 int,@P4 nvarchar(6),@P5 int,@P6 nvarchar(6),
N'插入df_至_sql_测试(id,txt)值(@P1,@P2),(@P3,@P4),(@P5,@P6),
0,N'row000',1,N'row001',2,N'row002'

问题是SQL Server存储过程(包括系统存储过程,如sp_prepexec)被限制为2100个参数,因此如果数据帧有100列,则to_SQL一次只能插入大约20行

我们可以使用

#df是一个现有的数据帧
#
#基于sp_PreExec参数计数的限制
tsql_chunksize=2097//len(df.columns)
#上限为1000(表值构造函数插入的行数限制)
如果tsql_chunksize>1000,则tsql_chunksize=1000,否则tsql_chunksize
#
df.to_sql('tablename',engine,index=False,如果_exists='replace',
方法='multi',chunksize=tsql\u chunksize)

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

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

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

发表评论