Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Utiliza este artículo para diagnosticar problemas de ejecución de consultas, tipo de datos, rendimiento, transacciones y copias masivas con el mssql-python controlador.
Problemas de ejecución de consultas
Tabla u objeto no encontrado
Síntomas:
ProgrammingError: [42S02] (208) Invalid object name 'TableName'.
Posibles causas y soluciones:
Contexto incorrecto de la base de datos
cursor.execute("SELECT DB_NAME()") print(cursor.fetchone()[0])Esquema no especificado
cursor.execute("SELECT * FROM dbo.TableName")La tabla no existe
cursor.execute(""" SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'TableName' """)
Error de sintaxis
Síntomas:
ProgrammingError: [42000] (102) Incorrect syntax near '...'.
Soluciones:
Prueba la sentencia SQL en SQL Server Management Studio (SSMS) para verificar la sintaxis.
Utiliza una consulta parametrizada en lugar de interpolación de cadenas:
# 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}, )
Errores de parámetros
Síntomas:
ProgrammingError: [07001] Wrong number of parameters
Soluciones:
Cuenta los marcadores de posición y los parámetros. Los conteos deben coincidir.
Elige el estilo de parámetro correcto:
# 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())
Problemas con el tipo de datos
Errores de conversión de fecha y hora
Síntomas:
DataError: [22007] Invalid datetime format
Solution:
Usa objetos en Python datetime en lugar de cadenas.
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())
Problemas de precisión decimal
Síntomas:
Los números aparecen truncados o redondeados incorrectamente.
Solution:
Uso decimal.Decimal para valores numéricos precisos:
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")},
)
Problemas de codificación Unicode
Síntomas:
Los caracteres especiales aparecen distorsionados o causan errores.
Soluciones:
Usa columnas nvarchar para los datos Unicode en tu base de datos.
Pasa las cadenas directamente. El controlador gestiona la codificación:
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())
Problemas de rendimiento
Ejecución lenta de consultas
Posibles causas y soluciones:
Índices faltantes: Revisa el plan de ejecución de consultas en SSMS.
Conjuntos de resultados grandes: Usar
fetchmany()en lugar defetchall():cursor.arraysize = 1000 while True: rows = cursor.fetchmany() if not rows: break process_rows(rows)Agrupación de conexiones desactivada: Habilitar agrupación:
import mssql_python mssql_python.pooling(max_size=20, idle_timeout=300)
Problemas de memoria con resultados grandes
Síntomas:
El proceso de Python se queda sin memoria.
Soluciones:
Transmita los resultados en flujo en lugar de cargar todas las filas en la memoria.
cursor.execute("SELECT * FROM LargeTable") for row in cursor: process_row(row)Usa la paginación del lado del servidor.
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
Problemas de transacciones
Alcance de tablas temporales con autocommit
Las tablas temporales de sesión (#tablename) que creas dentro de una transacción desaparecen cuando la transacción se revierte. Este comportamiento suele causar confusión cuando el autocommit está apagado, que es el valor predeterminado:
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")
Confirma inmediatamente después de crear una tabla temporal, o usa el modo autocommit:
cursor.execute("CREATE TABLE #TempData (ID INT, Name NVARCHAR(50))")
conn.commit()
cursor.execute("INSERT INTO #TempData VALUES (1, 'test')")
conn.commit()
Las sentencias DDL que requieren modo de compromiso automático, como CREATE DATABASE, fallan dentro de una transacción abierta. Establece el autocommit antes de ejecutarlos:
conn.autocommit = True
cursor.execute("CREATE DATABASE TestDB")
conn.autocommit = False
Transacción no comprometida
Síntomas:
Los cambios en los datos no persisten después de cerrar la conexión.
Solution:
Con autocommit=False, que es el valor predeterminado, llama a commit():
cursor.execute("CREATE TABLE #Products (Name NVARCHAR(100))")
cursor.execute(
"INSERT INTO #Products (Name) VALUES (%(name)s)",
{"name": "Widget"},
)
conn.commit()
Alternativamente, utiliza el modo de auto-commit:
conn = mssql_python.connect(connection_string, autocommit=True)
Errores de interbloqueo
Síntomas:
OperationalError: [40001] (1205) Transaction ... was deadlocked on lock resources with another process
Solution:
La lógica de reintentos gestiona el fallo inmediato, pero los bloqueos recurrentes indican un problema de diseño. Captura el gráfico de bloqueos y analiza las sentencias y tipos de bloqueo. Las soluciones más comunes incluyen estos cambios:
- Reordene las operaciones para que las transacciones en conflicto adquieran los bloqueos en la misma secuencia.
- Reducir el alcance de la transacción.
- Añadir índices apropiados para reducir la duración de los bloqueos.
Para una guía completa del análisis de bloqueos, consulta la guía de bloqueos. Si usas Azure SQL Database, consulta Analizar y prevenir bloqueos.
Problemas de carga masiva
Infracciones de restricciones durante la copia masiva
Síntomas:
RuntimeError: CHECK constraint ... Conflict occurred in database ...
RuntimeError: Cannot insert duplicate key ... violation of PRIMARY KEY constraint
Causa:
Los datos de tu lote incumplen las restricciones de la tabla, como las restricciones de clave primaria, de unicidad, de comprobación o de clave externa.
Solution:
Valida los datos antes de cargarlos. Para conjuntos de datos grandes, carga los datos en una tabla de staging y luego combínalos en el destino:
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()
Para patrones actualizar/insertar (upsert) con tablas de etapas, consulte Patrones de carga y movimiento de datos.
Errores de mapeo de columnas
Síntomas:
RuntimeError: Bulk copy failure - column count mismatch
Causa:
El número de columnas en tus datos no coincide con el número de columnas de la tabla objetivo, o las columnas están en el orden incorrecto.
Solution:
Asegúrate de que tus datos coincidan con el esquema de la tabla en el orden y la cantidad:
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)
Desajustes de tipo durante la copia en bloque
Síntomas:
Los datos se cargan, pero los valores están truncados, redondeados o son incorrectos.
Causa:
Los valores de Python no se corresponden claramente con los tipos de columna destino. Ejemplos comunes incluyen float valores cargados en columnas decimales , que pueden perder precisión, y cadenas sobredimensionadas cargadas en columnas de longitud fija.
Solution:
Usa tipos de Python que coincidan con tu esquema:
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)
Errores de vinculación de tipos de NumPy
Síntomas:
Los parámetros fallan silenciosamente o generan errores de tipo de datos cuando usas enteros o tipos flotantes NumPy.
Causa:
Tipos de NumPy como numpy.int64 y numpy.int32 no pasan isinstance(x, int) en NumPy 2.x. La inferencia de tipo del conductor no los reconoce, lo que provoca un comportamiento inesperado.
Solution:
Convierte los valores de NumPy a tipos nativos de Python antes de asignarlos:
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"]),
},
)
Para conjuntos de datos más grandes, utiliza las rutas de integración de Arrow o pandas . Estas rutas gestionan la conversión de tipos internamente.
Copia masiva con tablas temporales
Síntomas:
cursor.bulkcopy("#TempTable", data) genera RuntimeError: Invalid object name '#TempTable'.
Causa:
bulkcopy() No se pueden resolver las tablas temporales de sesión (#tablename) debido a las limitaciones de búsqueda de metadatos. Las tablas temporales globales (##tablename) y las tablas permanentes funcionan.
Solution:
Utiliza una tabla temporal global o una tabla de ensayo normal:
# 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)
Para conjuntos de datos pequeños donde prefieras una tabla temporal de sesión, usa executemany():
cursor.execute("CREATE TABLE #Staging (ID INT, Name NVARCHAR(50))")
cursor.executemany(
"INSERT INTO #Staging (ID, Name) VALUES (?, ?)",
rows,
)