Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

trường đếm to_sql pyodbc không chính xác hoặc lỗi cú pháp

Tại thời điểm câu hỏi này được đặt ra, pandas 0.23.0 vừa được phát hành. Phiên bản đó đã thay đổi hành vi mặc định của .to_sql() khỏi việc gọi DBAPI .executemany() phương pháp xây dựng hàm tạo giá trị bảng (TVC) sẽ cải thiện tốc độ tải lên bằng cách chèn nhiều hàng với một .execute() lệnh gọi của một câu lệnh INSERT. Thật không may, cách tiếp cận đó thường vượt quá giới hạn 2100 giá trị tham số của T-SQL cho một thủ tục được lưu trữ, dẫn đến lỗi được trích dẫn trong câu hỏi.

Ngay sau đó, bản phát hành gấu trúc tiếp theo đã thêm một method= đối số cho .to_sql() . Mặc định - method=None - khôi phục hành vi sử dụng .executemany() trước đây , trong khi chỉ định method="multi" sẽ nói với .to_sql() để sử dụng phương pháp tiếp cận TVC mới hơn.

Cùng thời gian đó, SQLAlchemy 1.3 đã được phát hành và nó đã thêm một fast_executemany=True đối số cho create_engine() đã cải thiện đáng kể tốc độ tải lên bằng cách sử dụng trình điều khiển ODBC của Microsoft cho SQL Server. Với sự cải tiến đó, method=None được chứng minh là nhanh nhất bằng method="multi" trong khi tránh giới hạn tham số 2100.

Vì vậy, với các phiên bản hiện tại của gấu trúc, SQLAlchemy và pyodbc, cách tốt nhất để sử dụng .to_sql() với trình điều khiển ODBC của Microsoft cho SQL Server là sử dụng fast_executemany=True và hành vi mặc định của .to_sql() , tức là,

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

Đây là phương pháp được khuyến nghị cho các ứng dụng chạy trên Windows, macOS và các biến thể Linux mà Microsoft hỗ trợ cho trình điều khiển ODBC của nó. Nếu bạn cần sử dụng FreeTDS ODBC, thì .to_sql() có thể được gọi bằng method="multi"chunksize= như mô tả bên dưới.

(Câu trả lời gốc)

Trước phiên bản gấu trúc 0.23.0, to_sql sẽ tạo một INSERT riêng biệt cho mỗi hàng trong 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'

Có lẽ để cải thiện hiệu suất, pandas 0.23.0 hiện tạo một hàm tạo giá trị bảng để chèn nhiều hàng cho mỗi lần gọi

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'

Vấn đề là các thủ tục được lưu trữ trong SQL Server (bao gồm các thủ tục được lưu trữ trong hệ thống như sp_prepexec ) được giới hạn ở 2100 tham số, vì vậy nếu DataFrame có 100 cột thì to_sql chỉ có thể chèn khoảng 20 hàng cùng một lúc.

Chúng tôi có thể tính toán chunksize được yêu cầu sử dụng

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

Tuy nhiên, cách tiếp cận nhanh nhất vẫn có thể là:

  • kết xuất DataFrame vào tệp CSV (hoặc tương tự), sau đó

  • yêu cầu Python gọi SQL Server bcp tiện ích để tải tệp đó lên bảng.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Làm thế nào để thực hiện một GROUP BY phân biệt chữ hoa chữ thường?

  2. Giá trị cột nhận dạng máy chủ SQL bắt đầu từ 0 thay vì 1

  3. Bảng tổng hợp và các cột nối

  4. Nhận thông tin dạng xem với dạng xem lược đồ thông tin VIEWS trong SQL Server

  5. Trả về các dòng có chứa các ký tự không phải chữ và số trong SQL Server