sql >> Databáze >  >> RDS >> Sqlserver

to_sql pyodbc count pole nesprávné nebo chyba syntaxe

V době, kdy byla tato otázka položena, byly právě vydány pandy 0.23.0. Tato verze změnila výchozí chování .to_sql() z volání DBAPI .executemany() metoda ke konstrukci konstruktoru hodnot tabulky (TVC), který by zlepšil rychlost nahrávání vložením více řádků pomocí jediného .execute() volání příkazu INSERT. Bohužel tento přístup často překračoval limit T-SQL 2100 hodnot parametrů pro uloženou proceduru, což vedlo k chybě citované v otázce.

Krátce nato bylo v následném vydání pand přidáno method= argument do .to_sql() . Výchozí – method=None – obnovilo předchozí chování použití .executemany() , přičemž uvedete method="multi" by řekl .to_sql() použít novější přístup TVC.

Přibližně ve stejnou dobu byla vydána SQLAlchemy 1.3 a přidala fast_executemany=True argument pro create_engine() což výrazně zlepšilo rychlost odesílání pomocí ovladačů ODBC společnosti Microsoft pro SQL Server. S tímto vylepšením method=None ukázalo se, že je přinejmenším stejně rychlé jako method="multi" a zároveň se vyhnout limitu 2100 parametrů.

Takže s aktuálními verzemi pand, SQLAlchemy a pyodbc je nejlepší přístup pro použití .to_sql() s ovladači ODBC společnosti Microsoft pro SQL Server je použití fast_executemany=True a výchozí chování .to_sql() , tj.

connection_uri = (
    "mssql+pyodbc://scott:tiger^[email protected]/db_name"
    "?driver=ODBC+Driver+17+for+SQL+Server"
)
engine = create_engine(connection_uri, fast_executemany=True)
df.to_sql("table_name", engine, index=False, if_exists="append")

Toto je doporučený přístup pro aplikace běžící na Windows, macOS a varianty Linuxu, které Microsoft podporuje pro svůj ovladač ODBC. Pokud potřebujete použít FreeTDS ODBC, pak .to_sql() lze volat pomocí method="multi" a chunksize= jak je popsáno níže.

(původní odpověď)

Před verzí pandy 0.23.0 to_sql by vygeneroval samostatný INSERT pro každý řádek v DataTable:

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'

Pravděpodobně za účelem zlepšení výkonu nyní pandas 0.23.0 generuje konstruktor tabulkových hodnot pro vložení více řádků na volání

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'

Problém je v tom, že uložené procedury SQL Serveru (včetně systémových uložených procedur jako sp_prepexec ) jsou omezeny na 2100 parametrů, takže pokud má DataFrame 100 sloupců, pak to_sql lze vložit pouze asi 20 řádků najednou.

Můžeme vypočítat požadovaný chunksize pomocí

# 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, index=False, if_exists='replace',
          method='multi', chunksize=tsql_chunksize)

Nejrychlejší přístup však stále pravděpodobně bude:

  • vypsat DataFrame do souboru CSV (nebo podobného) a poté

  • nechte Python zavolat SQL Server bcp nástroj k nahrání tohoto souboru do tabulky.



  1. Průvodce PGpool - Rady a postřehy:Část třetí

  2. Nejjednodušší způsob, jak ověřit odkaz na e-mail PHP

  3. Vložení do Oracle a načtení vygenerovaného ID sekvence

  4. Výjimka v hlavním vláknu java.sql.SQLException:Přístup odepřen uživateli ''@'localhost' (pomocí hesla:NE)