Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Driver mssql-python adalah driver Python pihak pertama Microsoft untuk Microsoft SQL. Jika Anda lebih suka opsi driver yang dikelola Microsoft, ia menawarkan:
- Tidak ada dependensi driver ODBC eksternal.
- Pool koneksi bawaan.
- Dukungan modern untuk Python 3.10+
- Autentikasi Microsoft Entra asli.
Perbedaan utama
| Feature | pyodbc | mssql-python |
|---|---|---|
| Gaya parameter |
qmark(?) |
qmark (?) dan pyformat (%(name)s) |
| Diperlukan driver ODBC | Yes | Tidak. |
| Pemanfaatan koneksi | Eksternal | Built-in |
| Python minimum | 3.6 | 3.10 |
callproc() |
Dukungan | Tidak diimplementasikan |
| Autocommit bawaan | Off | Off |
Langkah-langkah migrasi dasar
Langkah-langkah berikut mencakup perubahan kunci untuk memigrasikan aplikasi pyodbc ke mssql-python.
1. Perbarui impor
Ganti pyodbc impor dengan mssql_python:
Sebelum (pyodbc):
import pyodbc
Setelah (mssql-python):
import mssql_python
2. Perbarui string koneksi
Hapus DRIVER= kata kunci dan perbarui metode autentikasi:
Sebelum (pyodbc, membutuhkan driver ODBC):
conn = pyodbc.connect(
"DRIVER={ODBC Driver 18 for SQL Server};"
"SERVER=localhost;"
"DATABASE=AdventureWorks2022;"
"Trusted_Connection=yes;"
)
Setelah (mssql-python, tidak diperlukan driver, menggunakan autentikasi Microsoft Entra):
conn = mssql_python.connect(
"Server=<server>.database.windows.net;"
"Database=<database>;"
"Authentication=ActiveDirectoryDefault;"
"Encrypt=yes;"
)
3. Jaga agar pertanyaan Anda tetap as-is
Driver mssql-python mendukung kedua gaya parameter ? (qmark) dan %(name)s (pyformat). Kueri Anda yang sudah ada ? tetap berfungsi tanpa perubahan:
Sebelum (pyodbc):
cursor.execute("SELECT * FROM Production.Product WHERE ProductID = ? AND Color = ?", (1, "Red"))
Setelah (mssql-python, kueri yang sama):
cursor.execute("SELECT * FROM Production.Product WHERE ProductID = ? AND Color = ?", (1, "Red"))
4. Biarkan executemany apa adanya
Panggilan executemany yang sudah ada dengan tuple dan marker ? tetap berfungsi tanpa perubahan:
Sebelum (pyodbc):
cursor.execute("CREATE TABLE #MigrateDemo (ID INT, Name NVARCHAR(50))")
data = [(1, "Alice"), (2, "Bob"), (3, "Carol")]
cursor.executemany("INSERT INTO #MigrateDemo (ID, Name) VALUES (?, ?)", data)
Setelah (mssql-python, kode yang sama):
cursor.execute("DROP TABLE IF EXISTS #MigrateDemo")
cursor.execute("CREATE TABLE #MigrateDemo (ID INT, Name NVARCHAR(50))")
data = [(1, "Alice"), (2, "Bob"), (3, "Carol")]
cursor.executemany("INSERT INTO #MigrateDemo (ID, Name) VALUES (?, ?)", data)
Migrasi prosedur tersimpan
Driver mssql-python tidak mengimplementasikan callproc(). Bagian berikut menjelaskan cara menggunakan EXECUTE sebagai gantinya.
Gunakan EXECUTE untuk prosedur tersimpan
Driver pyodbc mendukung callproc(), tetapi driver mssql-python tidak. Gunakan EXECUTE sebagai gantinya:
Sebelum (pyodbc):
cursor.callproc("dbo.uspGetEmployeeManagers", (5,))
results = cursor.fetchall()
Setelah (mssql-python):
cursor.execute(
"EXECUTE dbo.uspGetEmployeeManagers @BusinessEntityID = %(id)s",
{"id": 5}
)
results = cursor.fetchall()
print(f"Got {len(results)} rows")
Parameter output
Gunakan variabel T-SQL untuk menangkap nilai output alih-alih mengandalkan callproc() parameter output:
Sebelum (pyodbc, menggunakan callproc):
params = (category_id, pyodbc.SQL_INTEGER)
cursor.callproc("dbo.GetProductCount", params)
count = params[1].value
Setelah (mssql-python, menggunakan variabel T-SQL):
cursor.execute(
"""
DECLARE @count INT;
SELECT @count = COUNT(*) FROM Production.Product
WHERE ProductSubcategoryID = %(cat_id)s;
SELECT @count AS ProductCount;
""",
{"cat_id": 1}
)
product_count = cursor.fetchval()
print(f"Product count: {product_count}")
Migrasi khusus fitur
Bagian berikut mencakup fitur pyodbc tertentu dan padanan mssql-pythonnya.
Rangkaian koneksi
| Kata kunci pyodbc | Kata kunci mssql-python | Catatan |
|---|---|---|
DRIVER={...} |
Tidak diperlukan | Driver ODBC telah disertakan secara internal. |
SERVER= |
Server= |
Tidak ada perubahan perilaku. |
DATABASE= |
Database= |
Tidak ada perubahan perilaku. |
Trusted_Connection= |
Trusted_Connection= |
Tidak ada perubahan perilaku. |
UID= / PWD= |
UID= / PWD= |
Tidak ada perubahan perilaku. |
Authentication= |
Authentication= |
Menerima nilai yang sama. |
Komit otomatis
Perilaku autocommit identik pada kedua driver:
Pyodbc:
conn.autocommit = True
pyodbc.connect(connection_string, autocommit=True)
mssql-python:
conn.autocommit = True
Sisipan massal
Untuk mempercepat batch besar INSERT , pengguna pyodbc mengatur fast_executemany = True. Driver mssql-python sudah mengoptimalkan executemany untuk batch berparameter, sehingga penyisipan dalam jumlah sedang tidak memerlukan flag khusus. Untuk pemuatan data besar, lebih suka bulkcopy(), yang mengalirkan baris melalui protokol salinan massal dan jauh lebih cepat daripada menerbitkan pernyataan individual INSERT . Untuk alur kerja lengkap, lihat Menggunakan salinan massal.
Pyodbc:
cursor.fast_executemany = True
cursor.executemany(query, data)
Setelah (mssql-python), moderasi batch dengan executemany:
cursor.execute("DROP TABLE IF EXISTS #BulkTarget")
cursor.execute("CREATE TABLE #BulkTarget (ID INT, Name NVARCHAR(50))")
data = [(i, f"Item {i}") for i in range(100)]
cursor.executemany("INSERT INTO #BulkTarget (ID, Name) VALUES (?, ?)", data)
conn.commit()
Setelah (mssql-python), muatan besar dengan bulkcopy (lebih disukai):
cursor.execute("IF OBJECT_ID('##BulkTarget') IS NOT NULL DROP TABLE ##BulkTarget")
cursor.execute("CREATE TABLE ##BulkTarget (ID INT, Name NVARCHAR(50))")
conn.commit() # Commit DDL before bulkcopy
data = [(i, f"Item {i}") for i in range(100)]
result = cursor.bulkcopy("##BulkTarget", data)
print(f"Bulk copied {result['rows_copied']} rows")
cursor.execute("DROP TABLE ##BulkTarget")
conn.commit()
Pabrik baris
driver mssql-python mengembalikan objek Row yang mendukung akses atribut secara bawaan, tanpa memerlukan row factory kustom:
Pyodbc (Pabrik Baris Kustom):
def namedtuple_row_factory(cursor):
from collections import namedtuple
columns = [col[0] for col in cursor.description]
Row = namedtuple("Row", columns)
return Row
mssql-python (akses atribut secara default):
cursor.execute("SELECT Name, ListPrice FROM Production.Product")
row = cursor.fetchone()
print(row.Name) # Attribute access works directly
print(row[0]) # Index access also works
Penanganan kesalahan
Driver mssql-python menggunakan hierarki pengecualian yang sama dengan pyodbc, sehingga sebagian besar penangan pengecualian hanya memerlukan perubahan nama modul.
Hierarki pengecualian
Nama kelas pengecualian dipetakan langsung di antara driver:
Pyodbc:
try:
cursor.execute(query)
except pyodbc.Error as e:
pass
except pyodbc.DatabaseError as e:
pass
except pyodbc.OperationalError as e:
pass
mssql-python:
try:
cursor.execute("SELECT TOP 1 * FROM Production.Product")
print(cursor.fetchone())
except mssql_python.Error as e:
pass
except mssql_python.DatabaseError as e:
pass
except mssql_python.OperationalError as e:
pass
Rincian kesalahan
Kedua driver mengekspos detail kesalahan melalui argumen pengecualian:
Pyodbc:
try:
cursor.execute(query)
except pyodbc.Error as e:
sqlstate = e.args[0]
message = e.args[1]
mssql-python:
try:
cursor.execute("SELECT TOP 1 * FROM NonExistentTable_XYZ")
except mssql_python.Error as e:
# Error message contains SQLSTATE and details
print(str(e))
Pemanfaatan koneksi
Driver mssql-python menyertakan pengumpulan koneksi secara default, sehingga pustaka pengumpulan eksternal tidak lagi diperlukan.
Hapus pengumpulan eksternal
Jika Anda menggunakan pengumpulan eksternal dengan pyodbc, driver mssql-python memilikinya:
Sebelum (kolam eksternal pyodbc):
from dbutils.pooled_db import PooledDB
pool = PooledDB(pyodbc, 5, driver="{ODBC Driver 18 for SQL Server}",
server="your_server", database="your_database",
uid="your_username", pwd="your_password")
conn = pool.connection()
Setelah (pooling bawaan mssql-python):
conn = mssql_python.connect(connection_string)
conn.close()
Mengonfigurasi kumpulan
Timpa ukuran pool dan batas waktu default dengan mssql_python.pooling():
import mssql_python
mssql_python.pooling()
Contoh migrasi lengkap
Berikut ini menunjukkan fungsi yang sama yang ditulis dengan pyodbc dan kemudian ditulis ulang dengan mssql-python.
Sebelum (pyodbc)
Versi ini menggunakan string koneksi pyodbc dengan DRIVER kata kunci:
import pyodbc
from datetime import date
def get_orders(customer_id: int, start_date: date):
conn = pyodbc.connect(
"DRIVER={ODBC Driver 18 for SQL Server};"
"SERVER=localhost;"
"DATABASE=AdventureWorks2022;"
"Trusted_Connection=yes;"
)
cursor = conn.cursor()
cursor.execute("""
SELECT SalesOrderID, OrderDate, TotalDue
FROM Sales.SalesOrderHeader
WHERE CustomerID = ? AND OrderDate >= ?
ORDER BY OrderDate DESC
""", (customer_id, start_date))
orders = []
for row in cursor:
orders.append({
"id": row.SalesOrderID,
"date": row.OrderDate,
"total": row.TotalDue
})
cursor.close()
conn.close()
return orders
Setelah (mssql-python)
Versi ini menghapus DRIVER kata kunci. Semua kueri, parameter, dan pola akses baris tetap identik:
import mssql_python
from datetime import date
def get_orders(customer_id: int, start_date: date):
conn = mssql_python.connect(
"Server=localhost;"
"Database=AdventureWorks2022;"
"Trusted_Connection=yes;"
)
cursor = conn.cursor()
cursor.execute("""
SELECT SalesOrderID, OrderDate, TotalDue
FROM Sales.SalesOrderHeader
WHERE CustomerID = ? AND OrderDate >= ?
ORDER BY OrderDate DESC
""", (customer_id, start_date))
orders = []
for row in cursor:
orders.append({
"id": row.SalesOrderID,
"date": row.OrderDate,
"total": row.TotalDue
})
cursor.close()
conn.close()
return orders
Satu-satunya perubahan adalah pernyataan impor dan string koneksi (tidak perlu DRIVER kata kunci). Setiap kueri, parameter, pola pengambilan, dan akses baris tetap identik.
Menguji migrasi
Sebelum menyelesaikan migrasi, jalankan kueri yang sama terhadap kedua driver dan bandingkan hasil untuk mengonfirmasi perilaku yang setara.
Memverifikasi perilaku yang setara
Gunakan fungsi perbandingan yang menjalankan kueri yang sama terhadap kedua driver dan menegaskan kecocokan hasilnya:
import pyodbc
import mssql_python
def compare_results(pyodbc_conn_str: str, mssql_conn_str: str, query: str):
"""Compare results from both drivers."""
# pyodbc query
pyodbc_conn = pyodbc.connect(pyodbc_conn_str)
pyodbc_cursor = pyodbc_conn.cursor()
pyodbc_cursor.execute(query)
pyodbc_results = pyodbc_cursor.fetchall()
pyodbc_conn.close()
# mssql-python query
mssql_conn = mssql_python.connect(mssql_conn_str)
mssql_cursor = mssql_conn.cursor()
mssql_cursor.execute(query)
mssql_results = mssql_cursor.fetchall()
mssql_conn.close()
# Compare
assert len(pyodbc_results) == len(mssql_results)
for p_row, m_row in zip(pyodbc_results, mssql_results):
assert tuple(p_row) == tuple(m_row)
print(f"Results match: {len(pyodbc_results)} rows")
Checklist
- [ ] Perbarui impor dari
pyodbckemssql_python. - [ ] Hapus
DRIVER=dari string koneksi. - [ ] Pertahankan kueri parameter
?yang ada (berfungsi tanpa perubahan). - [ ] Gunakan pernyataan
EXECUTEuntuk pemanggilan prosedur tersimpan. - [ ] Hapus konfigurasi pengumpulan koneksi eksternal.
- [ ] Perbarui nama kelas penanganan pengecualian.
- [ ] Uji semua kueri dan prosedur tersimpan.
- [ ] Verifikasi penanganan tipe data (terutama desimal dan tanggal).
- [ ] Hapus driver ODBC dari persyaratan penyebaran.