Felsökning mssql-python

Diagnostisera och lösa vanliga problem när du använder mssql-python-drivrutinen för att ansluta till SQL Server, Azure SQL Database, Azure SQL Managed Instance och SQL database i Microsoft Fabric.

Installationsproblem

Pip-installationen misslyckas eller byggs från källkoden

Symtom:

error: Microsoft Visual C++ 14.0 or greater is required
ERROR: Failed building wheel for mssql-python

Möjliga orsaker och lösningar:

  • Ingen förbyggd wheel för din plattform

  • Virtuell miljö aktiverad ej

    • Aktivera din virtuella miljö först. Att installera Python i systemet kan orsaka behörighetsfel eller konflikter.
    python -m venv .venv
    .venv\Scripts\activate
    pip install mssql-python
    

  • Saknade Linux-systembibliotek

Motstridiga installationer av drivrutiner

Symtom:

Importfel eller oväntat beteende efter installation av mssql-python tillsammans med pyodbc i samma miljö.

Lösningen

mssql-python och pyodbc kan samexistera. Om du ser konflikter, skapa en ren virtuell miljö:

python -m venv .venv --clear
.venv\Scripts\activate
pip install mssql-python

Anslutningsproblem

Kan inte ansluta till servern

Symtom:

OperationalError: [08001] (0) Client unable to establish connection

Möjliga orsaker och lösningar:

  • Server är inte tillgänglig

    • Verifiera att servernamnet och porten är korrekta.
    • Kontrollera nätverksanslutningen: ping servername eller telnet servername 1433.
    • Se till att brandväggen tillåter utgående anslutningar på port 1433.
  • SQL Server körs inte

    • Verifiera att SQL Server-tjänsten har startats.
    • För namngivna instanser, kontrollera att SQL Server Browser-tjänsten körs.
  • Azure SQL firewall rules

    • Lägg till din klient-IP i Azure SQL-brandväggsreglerna i Azure-portalen.
    • För Azure SQL Managed Instance, se till att du ansluter från ett tillåtet nätverk.
# Test basic connectivity
import socket
try:
    sock = socket.create_connection(("<server>.database.windows.net", 1433), timeout=5)
    print("TCP connection successful")
    sock.close()
except Exception as e:
    print(f"Cannot reach server: {e}")

Inloggningen misslyckades

Symtom:

OperationalError: [28000] (18456) Login failed for user 'username'.

Möjliga orsaker och lösningar:

  • Missanpassning i autentiseringsläge

    • För Azure SQL Database, Azure SQL Managed Instance och SQL database in Fabric, föredra ett Microsoft Entra-läge såsom Authentication=ActiveDirectoryDefault.
    • Om du medvetet använder SQL-autentisering, kontrollera att servern tillåter det och att du använder rätt inloggningsformat för den endpointen.
  • Felaktiga SQL-autentiseringsuppgifter

    • Verifiera användarnamn och lösenord.
    • För Azure SQL, inkludera det fullständiga användarnamnet: username@servername.
  • Användaren existerar inte i databasen

    • Verifiera att användaren har tillgång till den angivna databasen.
    • Kontrollera om inloggningen är mappad till en databasanvändare.
  • Autentisering ej konfigurerad

    • Använd Microsoft Entra-autentisering (rekommenderas): Authentication=ActiveDirectoryDefault.
    • Om du felsöker en lokal SQL Server som borde acceptera SQL-autentisering, kontrollera att SQL Server använder mixed mode-autentisering.

Tidsgräns för anslutning

Symtom:

OperationalError: [HYT00] (0) Timeout expired
OperationalError: [HYT01] (0) Connection timeout expired

Möjliga orsaker och lösningar:

  • Servern är långsam att svara

    • Öka tidsgränsen för anslutningen:
    conn = mssql_python.connect(connection_string, timeout=60)
    
  • Nätverksfördröjning

    • Kolla nätverksvägen till servern.
    • Överväg att använda en kortare nätverksväg eller VPN.
  • Server under hög belastning

    • Försök att ansluta under lågtrafiktid.
    • Kontakta din databasadministratör.

SSL-certifikatfel

Symtom:

OperationalError: [08001] SSL Provider: The certificate chain was issued by an authority that is not trusted

Lösningar:

För det första, föredra ett betrodd certifikat eller lokala utvecklingsmönster i Container och lokal utveckling. Använd TrustServerCertificate=yes endast för lokal utveckling mot en server som du kontrollerar.

För utveckling och testning med ett självsignerat certifikat:

conn = mssql_python.connect(
    "Server=<server>.database.windows.net;"
    "Database=<database>;"
    "Authentication=ActiveDirectoryDefault;"
    "Encrypt=yes;"
    "TrustServerCertificate=yes;"  # Don't use in production
)

Caution

TrustServerCertificate=yes är en endast lokal reservlösning. Ta inte med det in i delade devcontainers, CI-pipelines eller produktionsdistributioner. För bredare vägledning, se Kryptering och certifikat.

För produktion, se till att rätt certifikat installeras och använd:

conn = mssql_python.connect(
    "Server=<server>.database.windows.net;"
    "Database=<database>;"
    "Authentication=ActiveDirectoryDefault;"
    "Encrypt=yes;"
    "HostnameInCertificate=<server>.domain.com;"
)

Problem med frågeexekvering

Tabell eller objekt hittades ej

Symtom:

ProgrammingError: [42S02] (208) Invalid object name 'TableName'.

Möjliga orsaker och lösningar:

  • Fel databaskontext

    # Ensure you're connected to the correct database
    cursor.execute("SELECT DB_NAME()")
    print(cursor.fetchone()[0])
    
  • Schema ej specificerat

    # Use fully qualified name
    cursor.execute("SELECT * FROM dbo.TableName")
    
  • Tabellen finns inte

    # Check if table exists
    cursor.execute("""
         SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES 
         WHERE TABLE_NAME = 'TableName'
    """)
    

Syntaxfel

Symtom:

ProgrammingError: [42000] (102) Incorrect syntax near '...'.

Lösningar:

  1. Testa SQL i SSMS först för att verifiera syntaxen

  2. Kontrollera escaping av strängar – använd parametriserade frågor:

    # Wrong - vulnerable to syntax issues and SQL injection
    cursor.execute(f"SELECT * FROM Production.Product WHERE Name = '{name}'")
    
    # Correct - use parameters
    cursor.execute("SELECT * FROM Production.Product WHERE Name = %(name)s", {"name": name})
    

Parameterfel

Symtom:

ProgrammingError: [07001] Wrong number of parameters

Lösningar:

  1. Räkna platshållare och parametrar – de måste matcha

  2. Välj rätt parameterstil:

    # Qmark style - positional
    cursor.execute("SELECT * FROM Production.Product WHERE ProductID = ? AND Name LIKE ?", (1, "Adjustable%"))
    print(cursor.fetchone())
    
    # Pyformat style - named
    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

Lösningar:

Använd Python datetime-objekt istället för strängar:

from datetime import datetime

cursor.execute("CREATE TABLE #Events (EventDate DATETIME)")

# Wrong - this raises an error for invalid dates
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}")

# Correct - use Python datetime objects
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.

Lösningar:

Användning decimal.Decimal för exakta numeriska värden:

from decimal import Decimal

cursor.execute("CREATE TABLE #PriceDemo (ListPrice DECIMAL(10,2))")
# Preserve full precision
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:

  1. Använd NVARCHAR-kolumner för Unicode-data i din databas

  2. Skicka strängar direkt – drivrutinen hanterar teckenkodningen:

    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ör fetchall():

    cursor.arraysize = 1000
    while True:
         rows = cursor.fetchmany()
         if not rows:
             break
         process_rows(rows)
    
  • Anslutningspoolning inaktiverad: Aktivera anslutningspoolning:

    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:

  1. Strömresultat istället för att ladda in allt i minnet:

    cursor.execute("SELECT * FROM LargeTable")
    for row in cursor:  # Iterates one row at a time
        process_row(row)
    
  2. 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

Tillfälliga tabeller (#tablename) som skapas i en transaktion försvinner när transaktionen rullas tillbaka. Detta är en vanlig källa till förvirring när autocommit är avstängt (standardinställningen):

conn = mssql_python.connect(connection_string)  # autocommit=False by default
cursor = conn.cursor()

cursor.execute("CREATE TABLE #TempData (ID INT, Name NVARCHAR(50))")
cursor.execute("INSERT INTO #TempData VALUES (1, 'test')")

# If the connection rolls back (explicit or on error), #TempData disappears
conn.rollback()

# This fails: Invalid object name '#TempData'
cursor.execute("SELECT * FROM #TempData")

Fix: Verkställ direkt efter att du skapat en temporär tabell, eller använd autocommit-läge:

cursor.execute("CREATE TABLE #TempData (ID INT, Name NVARCHAR(50))")
conn.commit()  # Lock in the table definition

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 anslutningen stängts.

Solution:

Med autocommit=False (standard) måste du anropa commit():

cursor.execute("CREATE TABLE #Products (Name NVARCHAR(100))")
cursor.execute("INSERT INTO #Products (Name) VALUES (%(name)s)", {"name": "Widget"})
conn.commit()  # Don't forget this!

Eller använd autocommit-läget:

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:

Omprovlogik (se Ompröva logik) hanterar det omedelbara felet, men återkommande deadlocks indikerar ett designproblem. För att åtgärda grundorsaken, fånga deadlock-grafen och analysera vilka satser och låstyper som är involverade. Vanliga lösningar inkluderar omordningsoperationer så att konkurrerande transaktioner får lås i samma sekvens, minska transaktionsomfattningen och lägga 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 (primärnyckel, unik, CHECK eller främmande nyckel).

Lösningen

Validera data innan du laddar. För stora datamängder, läs först in dem i en mellantabell och sammanfoga dem sedan med måltabellen:

# Load into staging, then validate
cursor.execute("CREATE TABLE ##Staging (ID INT, Name NVARCHAR(100))")
cursor.bulkcopy("##Staging", rows)

# Check for duplicates before merging
cursor.execute("""
    SELECT s.ID FROM ##Staging s
    INNER JOIN dbo.Target t ON s.ID = t.ID
""")
dupes = cursor.fetchall()
if dupes:
    print(f"Skipping {len(dupes)} duplicate rows")

# Insert only non-duplicate rows
cursor.execute("""
    INSERT INTO dbo.Target (ID, Name)
    SELECT s.ID, s.Name FROM ##Staging s
    WHERE NOT EXISTS (SELECT 1 FROM dbo.Target 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 måltabellens kolumnantal, eller så är kolumnerna i fel ordning.

Lösningen

Se till att dina data matchar tabellschemat exakt i ordning och antal:

# Check the target table schema
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)

# Match your data to the column order
rows = [
    (1, "Widget", Decimal("19.99")),  # Must match table column order
    (2, "Gadget", Decimal("29.99")),
]
cursor.bulkcopy("dbo.MyTable", rows)

Typkonflikter vid bulkkopiering

Symtom:

Data läses in men värdena är avkortade, avrundade eller felaktiga.

Orsak:

Python-värden mappas inte rent till målkolumntyperna. Vanliga fall: float värden laddade i decimal kolumner (precisionsförlust), eller överdimensionerade strängar laddade i kolumner med fast längd.

Lösningen

Använd rätt Python-typer som matchar ditt schema:

from decimal import Decimal

# Use Decimal for decimal/numeric columns, not float
rows = [
    (1, "Widget", Decimal("19.99")),  # Correct
    # (1, "Widget", 19.99),           # Avoid: float loses precision
]
cursor.bulkcopy("dbo.Products", rows)

Fel vid typbindning i NumPy

Symtom:

Parametrar fallerar tyst eller utlöser datatypfel när NumPy-heltals- eller flyttalstyper används.

Orsak:

NumPy-typer som numpy.int64 och numpy.int32 klarar inte isinstance(x, int) i NumPy 2.x. Förarens typinferens känner inte igen dem, vilket orsakar oväntat beteende.

Lösningen

Konvertera numpy-värden till inbyggda Python-typer innan bindning:

import numpy as np

# Convert individual values
cursor.execute("SELECT * FROM Production.Product WHERE ProductID = %(product_id)s", {"product_id": int(np.int64(42))})

# Convert DataFrame values
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 datamängder bör du i stället använda integrationsalternativen Arrow eller pandas, som hanterar typkonvertering internt.

Bulkkopiering med tillfälliga tabeller

Symtom:

cursor.bulkcopy("#TempTable", data) höjer RuntimeError: Invalid object name '#TempTable'.

Orsak:

bulkcopy() Kan inte lösa sessionstemptabeller (#tablename) på grund av begränsningar i metadatauppslag. Globala tillfälliga tabeller (##tablename) och permanenta tabeller fungerar.

Lösningen

Använd en global temptabell eller en vanlig staging-tabell:

# Global temp table (visible to all sessions, dropped when last session disconnects)
cursor.execute("CREATE TABLE ##Staging (ID INT, Name NVARCHAR(50))")
cursor.bulkcopy("##Staging", rows)

# Or use a permanent staging table
cursor.execute("CREATE TABLE dbo.Staging (ID INT, Name NVARCHAR(50))")
cursor.bulkcopy("dbo.Staging", rows)

För små dataset där en sessionstemptabell föredras, använd executemany() istället:

cursor.execute("CREATE TABLE #Staging (ID INT, Name NVARCHAR(50))")
cursor.executemany("INSERT INTO #Staging (ID, Name) VALUES (?, ?)", rows)

Container- och CI-problem

Saknade systembibliotek på Linux

Symtom:

ImportError: libltdl.so.7: cannot open shared object file: No such file or directory
ImportError: libkrb5.so.3: cannot open shared object file

Lösningen

Installera de nödvändiga systempaketen. Paketen skiljer sig åt beroende på fördelning:

Distribution Installationskommando
Ubuntu/Debian sudo apt-get install libltdl7 libkrb5-3 libgssapi-krb5-2
Red Hat / Fedora sudo dnf install libtool-ltdl krb5-libs
Alpine apk add libltdl krb5-libs

För exempel på Dockerfile, se Container och lokal utveckling.

macOS SSL-fel efter installation

Symtom:

SSL-relaterade fel när man ansluter från macOS, särskilt på Apple Silicon.

Lösningen

Installera OpenSSL via Homebrew och sätt länkarflaggorna:

brew install openssl
export LDFLAGS="-L/opt/homebrew/opt/openssl/lib"
export CPPFLAGS="-I/opt/homebrew/opt/openssl/include"

Diagnosverktyg

Aktivera drivrutinsloggning

Använd mssql_python.setup_logging() för att aktivera omfattande DEBUG-loggning för felsökning. Alla drivrutinsoperationer loggas, inklusive SQL-satser, parametrar, interna ODBC-operationer och ändringar i anslutningstillstånd.

import mssql_python

# Enable logging to file (default)
mssql_python.setup_logging()

# Output to stdout (useful for CI/CD and containers)
mssql_python.setup_logging(output='stdout')

# Output to both file and stdout
mssql_python.setup_logging(output='both')

# Custom log file path (must use .txt, .log, or .csv extension)
mssql_python.setup_logging(log_file_path="/var/log/myapp/mssql.log")

Loggfiler skrivs i CSV-format och roterar automatiskt vid 512 MB med fem säkerhetskopior. Känslig data som lösenord och åtkomsttokens saneras automatiskt i loggutdata.

För att lägga till egna loggposter tillsammans med drivrutinsloggar, använd driver_logger:

from mssql_python.logging import driver_logger

mssql_python.setup_logging()

driver_logger.debug("[App] Starting data processing")
driver_logger.error("[App] Failed to process record")
# Your entries appear in the same file with the same format

Caution

Loggning medför prestandapåverkan. Aktivera det endast vid felsökning, inte i produktion som standard.

Få information om föraren

Hämta drivrutinsversionen och serverdetaljer från en aktiv anslutning:

import mssql_python

conn = mssql_python.connect(connection_string)

# Driver version
print(f"Version: {mssql_python.__version__}")

# Server information
print(f"Server name: {conn.getinfo(mssql_python.SQL_SERVER_NAME)}")
print(f"Database name: {conn.getinfo(mssql_python.SQL_DATABASE_NAME)}")

Kontrollera anslutningstillstånd

Testa om en anslutning fortfarande är öppen innan du försöker operationer:

try:
    cursor = conn.cursor()
    cursor.execute("SELECT 1")
    print("Connection is open")
except mssql_python.Error:
    print("Connection is closed or broken")

Snabb referens: Vanliga fel

Error SQLSTATE Vanlig orsak Snabbåtgärd
Klient kan inte upprätta anslutning 08001 Servern kan inte nås Kontrollera servernamn/port
Inloggningen misslyckades 28000 Felaktiga inloggningsuppgifter Verifiera användarnamn/lösenord
Tidsgränsen har upphört att gälla HYT00/HYT01 Långsamt nätverk Öka tidsgräns
Ogiltigt objektnamn 42S02 Felaktig tabell/felaktigt schema Använd fullt kvalificerade namn
Syntaxfel 42000 SQL-fel Använda parametriserade frågor
Begränsningsfel 23000 FK/PK-överträdelse Kontrollera dataintegriteten
Dödläge 40001 Låskonflikt Försök igen, analysera sedan deadlock-grafen