web-dev-qa-db-ja.com

to_sql pyodbc countフィールドが正しくないか、構文エラー

API WebサイトからJsonデータをダウンロードし、sqlalchemy、pyodbc、pandasのto_sql関数を使用して、そのデータをMSSQLサーバーに挿入しています。

最大10000行をダウンロードできますが、チャンクサイズを10に制限する必要があります。そうしないと、次のエラーが発生します。

DBAPIError:(pyodbc.Error)( '07002'、 '[07002] [Microsoft] [SQL Server Native Client 11.0] COUNTフィールドが正しくないか構文エラー(0)(SQLExecDirectW)')[SQL: 'INSERT INTO [TEMP_producing_entity_details]

ダウンロードする行は約5億行あり、この速度でクロールしているだけです。回避策に関するアドバイスはありますか?

おかげで、

10
Ryan

更新:

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'

おそらくパフォーマンスを向上させるために、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'

問題は、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)

ただし、最速のアプローチは次のようになります。

  • dataFrameをCSVファイル(または同様のもの)にダンプし、次に

  • Python SQL Server bcpユーティリティを呼び出して、そのファイルをテーブルにアップロードします。

14
Gord Thompson

Gord Thompsonの回答に基づいていくつかの変更を加えました。これにより、チャンクサイズが自動計算され、2100パラメータの制限に適合する最小の最も近い整数値に保持されます。

import math
df_num_of_cols=len(df.columns)
chunknum=math.floor(2100/df_num_of_cols)
df.to_sql('MY_TABLE',con=engine,schema='myschema',chunksize=chunknum,if_exists='append',method='multi',index=False )
0
Amit S