Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Använd denna artikel för att diagnostisera problem med frågeexekvering, datatyp, prestanda, transaktioner och bulkkopiering av drivrutinen mssql-python .
Problem med frågeexekvering
Tabell eller objekt hittades ej
Symtom:
ProgrammingError: [42S02] (208) Invalid object name 'TableName'.
Möjliga orsaker och lösningar:
Felaktig databaskontext
cursor.execute("SELECT DB_NAME()") print(cursor.fetchone()[0])Schema ej specificerat
cursor.execute("SELECT * FROM dbo.TableName")Tabellen finns inte
cursor.execute(""" SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'TableName' """)
Syntaxfel
Symtom:
ProgrammingError: [42000] (102) Incorrect syntax near '...'.
Lösningar:
Testa SQL-satsen i SQL Server Management Studio (SSMS) för att verifiera syntaxen.
Använd en parameteriserad fråga istället för stränginterpolation:
# 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}, )
Parameterfel
Symtom:
ProgrammingError: [07001] Wrong number of parameters
Lösningar:
Räkna platshållarna och parametrarna. Räkningarna måste stämma.
Välj rätt parameterstil:
# 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())
Datatypproblem
Fel vid konvertering av datum och tid
Symtom:
DataError: [22007] Invalid datetime format
Solution:
Använd Python-objekt datetime istället för strängar.
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())
Decimalprecisionsproblem
Symtom:
Siffror visas avkortade eller avrundade felaktigt.
Solution:
Användning decimal.Decimal för exakta numeriska värden:
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")},
)
Unicode-kodningsproblem
Symtom:
Specialtecken verkar osammanhängande eller orsakar fel.
Lösningar:
Använd nvarchar-kolumner för Unicode-data i din databas.
Passa strängarna direkt. Drivrutinen hanterar kodningen:
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())
Prestandaproblem
Långsam frågeexekvering
Möjliga orsaker och lösningar:
Saknade index: Kontrollera frågeexekveringsplanen i SSMS.
Stora resultatmängder: Använd
fetchmany()istället förfetchall():cursor.arraysize = 1000 while True: rows = cursor.fetchmany() if not rows: break process_rows(rows)Anslutningspoolning inaktiverad: Aktivera poolning:
import mssql_python mssql_python.pooling(max_size=20, idle_timeout=300)
Minnesproblem med stora resultat
Symtom:
Python-processen får slut på minne.
Lösningar:
Strömma resultat istället för att ladda alla rader i minnet.
cursor.execute("SELECT * FROM LargeTable") for row in cursor: process_row(row)Använd serverside-paginering.
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
Transaktionsproblem
Temporär tabellscoping med autocommit
Sessionstemporära tabeller (#tablename) du skapar i en transaktion försvinner när transaktionen rullas tillbaka. Detta beteende orsakar ofta förvirring när autocommit är avstängt, vilket är standard:
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")
Bekräfta omedelbart efter att du har skapat en temporär tabell, eller använd autocommit-läge:
cursor.execute("CREATE TABLE #TempData (ID INT, Name NVARCHAR(50))")
conn.commit()
cursor.execute("INSERT INTO #TempData VALUES (1, 'test')")
conn.commit()
DDL-satser som kräver autocommit mode, såsom CREATE DATABASE, misslyckas inom en öppen transaktion. Ställ in autocommit innan du kör dem:
conn.autocommit = True
cursor.execute("CREATE DATABASE TestDB")
conn.autocommit = False
Transaktion som inte är genomförd
Symtom:
Dataändringar kvarstår inte efter att du stängt anslutningen.
Solution:
Med autocommit=False, vilket är standard, anropa commit():
cursor.execute("CREATE TABLE #Products (Name NVARCHAR(100))")
cursor.execute(
"INSERT INTO #Products (Name) VALUES (%(name)s)",
{"name": "Widget"},
)
conn.commit()
Alternativt, använd autocommit-läge:
conn = mssql_python.connect(connection_string, autocommit=True)
Dödlägesfel
Symtom:
OperationalError: [40001] (1205) Transaction ... was deadlocked on lock resources with another process
Solution:
Ompröva-logiken hanterar det omedelbara felet, men återkommande deadlocks indikerar ett designproblem. Samla in dödlägesgrafen och analysera instruktionerna och låstyperna. Vanliga lösningar inkluderar dessa förändringar:
- Ordna om operationerna så att konkurrerande transaktioner inhämtar lås i samma ordning.
- Minska transaktionsomfattningen.
- Lägg till lämpliga index för att minska låsets varaktighet.
För en fullständig genomgång av deadlock-analys, se Deadlocks-guiden. Om du använder Azure SQL Database, se Analysera och förhindra deadlocks.
Bulklastproblem
Begränsningsbrott under bulkkopiering
Symtom:
RuntimeError: CHECK constraint ... Conflict occurred in database ...
RuntimeError: Cannot insert duplicate key ... violation of PRIMARY KEY constraint
Orsak:
Data i din batch bryter mot tabellbegränsningar såsom primärnyckel-, unik-, kontroll- eller främmande nyckelbegränsningar.
Solution:
Validera data innan du laddar den. För stora datamängder, ladda in datan i en stagingtabell och slå sedan ihop den med målet:
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()
För upsert-mönster med stagingtabeller, se Data loading and movement patterns.
Fel vid kolumnmappning
Symtom:
RuntimeError: Bulk copy failure - column count mismatch
Orsak:
Antalet kolumner i din data stämmer inte överens med antalet kolumner i måltabellen, eller så är kolumnerna i fel ordning.
Solution:
Se till att dina data matchar tabellschemat i ordning och antal:
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)
Typkonflikter vid bulkkopiering
Symtom:
Data läses in, men värdena är trunkerade, avrundade eller felaktiga.
Orsak:
Python-värden mappas inte rent till målkolumntyperna. Vanliga exempel inkluderar float värden som laddas i decimalkolumner , vilka kan tappa precision, och överdimensionerade strängar som laddas i kolumner med fast längd.
Solution:
Använd Python-typer som matchar ditt 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)
Bindningsfel av NumPy-typ
Symtom:
Parametrar misslyckas tyst eller ger datatypfel när du använder NumPy heltals- eller flyttal-typer.
Orsak:
NumPy-typer som numpy.int64 och numpy.int32 passerar isinstance(x, int) inte i NumPy 2.x. Förarens typinferens känner inte igen dem, vilket orsakar oväntat beteende.
Solution:
Konvertera NumPy-värden till inbyggda Python-typer innan du binder dem:
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"]),
},
)
För större datauppsättningar, använd integreringsvägarna för Arrow eller pandas. Dessa vägar hanterar typkonvertering internt.
Bulkkopiering med temporära tabeller
Symtom:
cursor.bulkcopy("#TempTable", data) höjer RuntimeError: Invalid object name '#TempTable'.
Orsak:
bulkcopy() Kan inte lösa sessionstemporära tabeller (#tablename) på grund av begränsningar i metadatauppslag. Globala tillfälliga tabeller (##tablename) och permanenta tabeller fungerar.
Solution:
Använd en global temptabell eller en vanlig staging-tabell:
# 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)
För små datauppsättningar där du föredrar en temporär sessionstabell, använd executemany():
cursor.execute("CREATE TABLE #Staging (ID INT, Name NVARCHAR(50))")
cursor.executemany(
"INSERT INTO #Staging (ID, Name) VALUES (?, ?)",
rows,
)