sql >> Database teknologi >  >> RDS >> Sqlserver

to_sql pyodbc count felt forkert eller syntaksfejl

På det tidspunkt, hvor dette spørgsmål blev stillet, var pandas 0.23.0 netop blevet frigivet. Denne version ændrede standardadfærden for .to_sql() fra at kalde DBAPI'en .executemany() metode til at konstruere en tabelværdikonstruktør (TVC), der ville forbedre uploadhastigheden ved at indsætte flere rækker med en enkelt .execute() kald af en INSERT-sætning. Desværre overskred denne tilgang ofte T-SQL's grænse på 2100 parameterværdier for en lagret procedure, hvilket førte til fejlen nævnt i spørgsmålet.

Kort efter tilføjede en efterfølgende udgivelse af pandaer en method= argument til .to_sql() . Standarden – method=None – gendannede den tidligere adfærd ved at bruge .executemany() , mens du angiver method="multi" ville fortælle .to_sql() at bruge den nyere TVC-tilgang.

Omtrent på samme tid blev SQLAlchemy 1.3 frigivet, og den tilføjede en fast_executemany=True argument til create_engine() hvilket i høj grad forbedrede uploadhastigheden ved hjælp af Microsofts ODBC-drivere til SQL Server. Med denne forbedring, method=None viste sig at være mindst lige så hurtig som method="multi" og samtidig undgå grænsen på 2100 parametre.

Så med nuværende versioner af pandaer, SQLAlchemy og pyodbc er den bedste tilgang til at bruge .to_sql() med Microsofts ODBC-drivere til SQL Server er at bruge fast_executemany=True og standardadfærden for .to_sql() , dvs.

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

Dette er den anbefalede tilgang til apps, der kører på Windows, macOS og de Linux-varianter, som Microsoft understøtter til sin ODBC-driver. Hvis du skal bruge FreeTDS ODBC, så .to_sql() kan kaldes med method="multi" og chunksize= som beskrevet nedenfor.

(Oprindeligt svar)

Før pandas version 0.23.0, to_sql ville generere en separat INSERT for hver række i datatabellen:

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'

Sandsynligvis for at forbedre ydeevnen genererer pandas 0.23.0 nu en tabelværdikonstruktør til at indsætte flere rækker pr. opkald

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'

Problemet er, at SQL Server-lagrede procedurer (inklusive systemlagrede procedurer som sp_prepexec ) er begrænset til 2100 parametre, så hvis DataFrame har 100 kolonner, så to_sql kan kun indsætte omkring 20 rækker ad gangen.

Vi kan beregne den nødvendige chunksize ved hjælp af

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

Den hurtigste tilgang vil dog sandsynligvis stadig være:

  • dump DataFrame til en CSV-fil (eller lignende), og derefter

  • få Python til at kalde SQL Serveren bcp værktøj til at uploade den fil til tabellen.



  1. LØST:Microsoft Office 365 version 2009 kan ødelægge din databaseapplikation

  2. Hvordan indtaster man specialtegn som &i Oracle-databasen?

  3. mysql_insert_id alternativ til postgresql

  4. UTL_FILE.FREMOVE Eksempel:Slet en fil i Oracle