Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Usa questo articolo per diagnosticare problemi di esecuzione delle query, tipo di dato, prestazioni, transazioni e copie di massa con il mssql-python driver.
Problemi di esecuzione delle query
Tabella o oggetto non trovato
Sintomi:
ProgrammingError: [42S02] (208) Invalid object name 'TableName'.
Possibili cause e soluzioni:
Contesto errato del database
cursor.execute("SELECT DB_NAME()") print(cursor.fetchone()[0])Schema non specificato
cursor.execute("SELECT * FROM dbo.TableName")Il tavolo non esiste
cursor.execute(""" SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'TableName' """)
Errore di sintassi
Sintomi:
ProgrammingError: [42000] (102) Incorrect syntax near '...'.
Soluzioni:
Testa la dichiarazione SQL in SQL Server Management Studio (SSMS) per verificare la sintassi.
Usa una query parametrizzata invece dell'interpolazione delle stringhe:
# Don't use string interpolation for query parameters. cursor.execute(f"SELECT * FROM Production.Product WHERE Name = '{name}'") # Use parameters. cursor.execute( "SELECT * FROM Production.Product WHERE Name = %(name)s", {"name": name}, )
Errori dei parametri
Sintomi:
ProgrammingError: [07001] Wrong number of parameters
Soluzioni:
Conta i segnaposto e i parametri. I conteggi devono corrispondere.
Scegli lo stile di parametro corretto:
# Qmark style: positional parameters cursor.execute( "SELECT * FROM Production.Product " "WHERE ProductID = ? AND Name LIKE ?", (1, "Adjustable%"), ) print(cursor.fetchone()) # Pyformat style: named parameters cursor.execute( "SELECT * FROM Production.Product " "WHERE ProductID = %(id)s AND Name LIKE %(name)s", {"id": 1, "name": "Adjustable%"}, ) print(cursor.fetchone())
Conteggi di righe errati in lotti multi-risultato
Se rowcount ripete il conteggio della prima istruzione dopo nextset(), aggiorna il driver. Ogni aggiornamento riuscito nextset() aggiorna il conteggio per il nuovo risultato. Un risultato che produce una riga inizia -1 prima del recupero. Verifica cursor.description prima di recuperare perché i risultati delle modifiche dei dati contengono conteggi invece di righe.
Disattiva SET NOCOUNT quando hai bisogno dei risultati delle righe interessate. Per un esempio completo, vedi Monitora ogni risultato in un batch.
Problemi con i tipi di dati
Errori di conversione di data e ora
Sintomi:
DataError: [22007] Invalid datetime format
Soluzione:
Usa oggetti Python datetime invece delle stringhe.
from datetime import datetime
cursor.execute("CREATE TABLE #Events (EventDate DATETIME)")
# This value raises an error because the date is invalid.
try:
cursor.execute(
"INSERT INTO #Events (EventDate) VALUES (%(event_date)s)",
{"event_date": "2024-13-45"},
)
except Exception as e:
print(f"Expected error: {e}")
# Use a Python datetime object.
cursor.execute(
"INSERT INTO #Events (EventDate) VALUES (%(event_date)s)",
{"event_date": datetime(2024, 3, 15)},
)
cursor.execute("SELECT EventDate FROM #Events")
print(cursor.fetchone())
Il costruttore Timestamp richiede un argomento in microsecondi
Se Timestamp(year, month, day, hour, minute, second) genera TypeError per un argomento microsecond mancante, aggiorna mssql-python. Il driver corrente accetta il costruttore DB-API a sei argomenti e imposta microsecond a zero per impostazione predefinita. Per maggiori informazioni, vedi DB-API costruttore di timestamp.
Problemi di precisione decimale
Sintomi:
I numeri appaiono troncati o arrotondati in modo errato.
Soluzione:
Uso decimal.Decimal per valori numerici precisi:
from decimal import Decimal
cursor.execute("CREATE TABLE #PriceDemo (ListPrice DECIMAL(10, 2))")
cursor.execute(
"INSERT INTO #PriceDemo (ListPrice) VALUES (%(list_price)s)",
{"list_price": Decimal("19.99")},
)
Problemi di codifica Unicode
Sintomi:
I caratteri speciali appaiono distorti o causano errori.
Soluzioni:
Usa le colonne nvarchar per i dati Unicode nel tuo database.
Passa le corde direttamente. Il driver gestisce la codifica:
cursor.execute("CREATE TABLE #UnicodeDemo (Name NVARCHAR(50))") cursor.execute( "INSERT INTO #UnicodeDemo (Name) VALUES (%(name)s)", {"name": "日本語"}, ) cursor.execute("SELECT Name FROM #UnicodeDemo") print(cursor.fetchone())
Problemi di prestazioni
Esecuzione lenta delle query
Possibili cause e soluzioni:
Indici mancanti: Controlla il piano di esecuzione delle query in SSMS.
Grandi set di risultati: Usa
fetchmany()invece difetchall():cursor.arraysize = 1000 while True: rows = cursor.fetchmany() if not rows: break process_rows(rows)Aggregazione della connessione disabilitata: Abilita il pooling:
import mssql_python mssql_python.pooling(max_size=20, idle_timeout=300)
Problemi di memoria con risultati grandi
Sintomi:
Il processo Python esaurisce la memoria.
Soluzioni:
Trasmetti i risultati in streaming anziché caricare tutte le righe in memoria.
cursor.execute("SELECT * FROM LargeTable") for row in cursor: process_row(row)Usa la paginazione lato server.
page_size = 1000 offset = 0 while True: cursor.execute( "SELECT * FROM LargeTable ORDER BY ID " "OFFSET ? ROWS FETCH NEXT ? ROWS ONLY", (offset, page_size), ) rows = cursor.fetchall() if not rows: break process_rows(rows) offset += page_size
Problemi di transazione
Visibilità delle tabelle temporanee con autocommit
Le tabelle temporanee di sessione (#tablename) che crei all'interno di una transazione scompaiono quando la transazione viene annullata. Questo comportamento causa spesso confusione quando l'autocommit è disattivato, che è il valore predefinito:
conn = mssql_python.connect(connection_string)
cursor = conn.cursor()
cursor.execute("CREATE TABLE #TempData (ID INT, Name NVARCHAR(50))")
cursor.execute("INSERT INTO #TempData VALUES (1, 'test')")
# An explicit rollback or an error removes #TempData.
conn.rollback()
# This statement fails with "Invalid object name '#TempData'".
cursor.execute("SELECT * FROM #TempData")
Effettua il commit immediatamente dopo aver creato una tabella temporanea, oppure usa la modalità autocommit:
cursor.execute("CREATE TABLE #TempData (ID INT, Name NVARCHAR(50))")
conn.commit()
cursor.execute("INSERT INTO #TempData VALUES (1, 'test')")
conn.commit()
Le istruzioni DDL che richiedono la modalità autocommitto, come CREATE DATABASE, falliscono all'interno di una transazione aperta. Imposta l'autocommit prima di eseguirli:
conn.autocommit = True
cursor.execute("CREATE DATABASE TestDB")
conn.autocommit = False
Transazione non commessa
Sintomi:
I cambiamenti nei dati non persistono dopo aver chiuso la connessione.
Soluzione:
Con autocommit=False, che è il valore predefinito, chiamiamo commit():
cursor.execute("CREATE TABLE #Products (Name NVARCHAR(100))")
cursor.execute(
"INSERT INTO #Products (Name) VALUES (%(name)s)",
{"name": "Widget"},
)
conn.commit()
In alternativa, usa la modalità autocommit:
conn = mssql_python.connect(connection_string, autocommit=True)
Errori di deadlock
Sintomi:
OperationalError: [40001] (1205) Transaction ... was deadlocked on lock resources with another process
Soluzione:
La logica di ritentazione gestisce il guasto immediato, ma blocchi ricorrenti indicano un problema di progettazione. Acquisisci il grafo del deadlock e analizza le istruzioni e i tipi di blocco. Le soluzioni più comuni includono queste modifiche:
- Riordina le operazioni affinché le transazioni concorrenti acquisiscano i lock nella stessa sequenza.
- Riduci la portata delle transazioni.
- Aggiungere indici adeguati per ridurre la durata del blocco.
Per una guida completa dell'analisi degli sblocchi, consulta la guida Deadlocks. Se usi database SQL di Azure, vedi Analizza e preveni blocchi.
Problemi di carico in blocco
La copia in blocco fallisce dopo un aggiornamento del pacchetto
Se le query normali funzionano ma bulkcopy() o bulkcopy_arrow() non riescono a importare o caricare il modulo nativo di copia bulk, aggiorna il driver con dipendenze:
python -m pip install --upgrade mssql-python
python -m pip check
Il driver richiede un runtime corrispondente mssql-python-rs. Un aggiornamento parziale o un'installazione con --no-deps possono lasciare pacchetti incompatibili installati. Se usi un indice privato dei pacchetti, replica entrambi i pacchetti companion e mantieni i pin di dipendenza dichiarati dal driver. Per le versioni bloccate correnti, vedi Requisiti di dipendenza.
Nomi di destinazione non supportati
bulkcopy() e bulkcopy_arrow() accettano al massimo tre parti identificative. Un nome in quattro parti come server.database.schema.table genera RuntimeError durante la ricerca dei metadati prima che vengano inviate le righe. Connettiti direttamente al server di destinazione e usa un nome di tabella in una, due o tre parti. Per errori di escape delle parentesi e nomi malformati, vedi Nomi delle tabelle target.
Unicode o secondi frazionari persi durante la copia in massa
Aggiorna il driver se la copia in massa corrompe il testo UTF-8 o tronca frazioni di secondo quando carica valori datetime2 compatibili. L'attuale runtime di copia in massa gestisce il testo UTF-8 e mantiene la precisione datetime2 disponibile nei tipi di sorgente e destinazione.
Usa nvarchar o una collazione UTF-8 su varchar per il testo Unicode. I valori Python datetime e i metodi Arrow fetch del driver sono limitati ai microsecondi. Per valori di 100 nanosecondi già presenti in una colonna di timestamp di nanosecondi Arrow, caricare in datetime2(7) senza prima convertire in Pythondatetime. Per maggiori informazioni, vedi Unicode e precisione temporale e Arrow temporal precision.
Violazioni dei vincoli durante la copia di massa
Sintomi:
RuntimeError: CHECK constraint ... Conflict occurred in database ...
RuntimeError: Cannot insert duplicate key ... violation of PRIMARY KEY constraint
Causa:
I dati nel tuo batch violano vincoli di tabella come la chiave primaria, la chiave unica, la chiave di controllo o la chiave esterna.
Soluzione:
Valida i dati prima di caricarli. Per grandi dataset, carichi i dati in una tabella di staging e poi uniscili al target:
cursor.execute("CREATE TABLE ##Staging (ID INT, Name NVARCHAR(100))")
cursor.bulkcopy("##Staging", rows)
# Check for duplicate rows before the merge.
cursor.execute("""
SELECT s.ID
FROM ##Staging AS s
INNER JOIN dbo.Target AS t
ON s.ID = t.ID
""")
dupes = cursor.fetchall()
if dupes:
print(f"Skipping {len(dupes)} duplicate rows")
# Insert rows that don't exist in the target.
cursor.execute("""
INSERT INTO dbo.Target (ID, Name)
SELECT s.ID, s.Name
FROM ##Staging AS s
WHERE NOT EXISTS (
SELECT 1
FROM dbo.Target AS t
WHERE t.ID = s.ID
)
""")
conn.commit()
Per i modelli di upsert con tabelle di staging, vedi i modelli di caricamento e spostamento dei dati.
Errori di mappatura delle colonne
Sintomi:
RuntimeError: Bulk copy failure - column count mismatch
Causa:
Il numero di colonne nei tuoi dati non corrisponde al numero di colonne target della tabella, oppure le colonne sono nell'ordine sbagliato.
Soluzione:
Assicurati che i dati corrispondano allo schema della tabella per ordine e numero:
from decimal import Decimal
cursor.execute("""
SELECT COLUMN_NAME, DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'MyTable'
ORDER BY ORDINAL_POSITION
""")
for col in cursor.fetchall():
print(col)
rows = [
(1, "Widget", Decimal("19.99")),
(2, "Gadget", Decimal("29.99")),
]
cursor.bulkcopy("dbo.MyTable", rows)
Discorrispondenze di tipo durante la copia di massa
Sintomi:
Carichi dati, ma i valori sono troncati, arrotondati o erratati.
Causa:
I valori di Python non corrispondono nettamente ai tipi di colonne di destinazione. Esempi comuni includono float valori caricati in colonne decimali , che possono perdere precisione, e stringhe sovradimensionate caricate in colonne di lunghezza fissa.
Soluzione:
Usa tipi Python che corrispondono al tuo schema:
from decimal import Decimal
rows = [
# Use Decimal for decimal and numeric columns.
(1, "Widget", Decimal("19.99")),
# Avoid float values because they can lose precision.
# (1, "Widget", 19.99),
]
cursor.bulkcopy("dbo.Products", rows)
Errori di binding dei tipi NumPy
Sintomi:
I parametri falliscono silenziosamente o aumentano errori di tipo di dati quando si usano interi o tipi float NumPy.
Causa:
I tipi NumPy come numpy.int64 e numpy.int32 non superano isinstance(x, int) in NumPy 2.x. L'inferenza di tipo del conducente non li riconosce, il che provoca comportamenti inaspettati.
Soluzione:
Converti i valori NumPy in tipi nativi di Python prima di assegnarli:
import numpy as np
cursor.execute(
"SELECT * FROM Production.Product WHERE ProductID = %(product_id)s",
{"product_id": int(np.int64(42))},
)
for _, row in df.iterrows():
cursor.execute(
"INSERT INTO #Orders (ProductID, Qty) "
"VALUES (%(product_id)s, %(qty)s)",
{
"product_id": int(row["ProductID"]),
"qty": int(row["Qty"]),
},
)
Per dataset più grandi, usa i percorsi di integrazione Arrow o pandas . Questi percorsi gestiscono internamente la conversione dei tipi.
Copia in blocco con tabelle temporanee
Sintomi:
cursor.bulkcopy("#TempTable", data) solleva RuntimeError: Invalid object name '#TempTable'.
Causa:
bulkcopy() Non posso risolvere le tabelle temporaneali della sessione (#tablename) a causa delle limitazioni di ricerca dei metadati. Le tabelle temporanee globali (##tablename) e le tabelle permanenti funzionano.
Soluzione:
Usa una tabella temporanea globale o una tabella di staging normale:
# A global temp table is visible to all sessions and is dropped
# when the last session disconnects.
cursor.execute("CREATE TABLE ##Staging (ID INT, Name NVARCHAR(50))")
cursor.bulkcopy("##Staging", rows)
# Alternatively, use a permanent staging table.
cursor.execute("CREATE TABLE dbo.Staging (ID INT, Name NVARCHAR(50))")
cursor.bulkcopy("dbo.Staging", rows)
Per piccoli dataset dove preferisci una tabella temporanea di sessione, usa executemany():
cursor.execute("CREATE TABLE #Staging (ID INT, Name NVARCHAR(50))")
cursor.executemany(
"INSERT INTO #Staging (ID, Name) VALUES (?, ?)",
rows,
)