sql >> Database >  >> RDS >> Sqlserver

to_sql pyodbc count veld onjuist of syntaxisfout

Op het moment dat deze vraag werd gesteld, waren panda's 0.23.0 net vrijgelaten. Die versie veranderde het standaardgedrag van .to_sql() van het aanroepen van de DBAPI .executemany() methode voor het construeren van een table-value constructor (TVC) die de uploadsnelheid zou verbeteren door meerdere rijen in te voegen met een enkele .execute() aanroep van een INSERT-instructie. Helaas overschreed die aanpak vaak de T-SQL-limiet van 2100 parameterwaarden voor een opgeslagen procedure, wat leidde tot de in de vraag genoemde fout.

Kort daarna voegde een volgende release van panda's een method= . toe argument naar .to_sql() . De standaard - method=None – herstelde het eerdere gedrag van het gebruik van .executemany() , terwijl u method="multi" . specificeert zou vertellen .to_sql() om de nieuwere TVC-aanpak te gebruiken.

Rond dezelfde tijd werd SQLAlchemy 1.3 uitgebracht en werd een fast_executemany=True toegevoegd argument voor create_engine() die de uploadsnelheid aanzienlijk verbeterde met behulp van Microsoft's ODBC-stuurprogramma's voor SQL Server. Met die verbetering, method=None bleek minstens zo snel te zijn als method="multi" terwijl de limiet van 2100 parameters wordt vermeden.

Dus met de huidige versies van panda's, SQLAlchemy en pyodbc, de beste aanpak voor het gebruik van .to_sql() met Microsoft's ODBC-stuurprogramma's voor SQL Server is het gebruik van fast_executemany=True en het standaardgedrag van .to_sql() , d.w.z.

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")

Dit is de aanbevolen aanpak voor apps die worden uitgevoerd op Windows, macOS en de Linux-varianten die Microsoft ondersteunt voor zijn ODBC-stuurprogramma. Als u FreeTDS ODBC moet gebruiken, dan .to_sql() kan worden aangeroepen met method="multi" en chunksize= zoals hieronder beschreven.

(Oorspronkelijke antwoord)

Voorafgaand aan panda's versie 0.23.0, to_sql zou een aparte INSERT genereren voor elke rij in de 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'

Vermoedelijk om de prestaties te verbeteren, genereert pandas 0.23.0 nu een tabelwaarde-constructor om meerdere rijen per aanroep in te voegen

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'

Het probleem is dat SQL Server opgeslagen procedures (inclusief systeem opgeslagen procedures zoals sp_prepexec) ) zijn beperkt tot 2100 parameters, dus als het DataFrame 100 kolommen heeft, dan to_sql kan slechts ongeveer 20 rijen tegelijk invoegen.

We kunnen de vereiste chunksize berekenen met behulp van

# 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)

De snelste benadering is echter waarschijnlijk nog steeds:

  • dump het DataFrame naar een CSV-bestand (of iets dergelijks), en dan

  • laat Python de SQL Server bcp aanroepen hulpprogramma om dat bestand naar de tabel te uploaden.



  1. Hoe installeer ik Azure Data Studio op een Mac

  2. postgreSQL - in vs any

  3. Voorbeelden van het converteren van 'date' naar 'datetimeoffset' in SQL Server (T-SQL)

  4. MySQL-foutcode:1175 tijdens UPDATE in MySQL Workbench