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())
Conteos incorrectos de filas en lotes de varios resultados
Si rowcount repite el conteo de la primera instrucción después de nextset(), actualice el driver. Cada actualización exitosa nextset() actualiza el recuento del nuevo resultado. Un resultado que produce filas comienza en -1 antes de recuperar los datos. Comprueba esto: cursor.description antes de obtener datos porque los resultados de modificación de datos contienen recuentos en lugar de filas.
No incluyas SET NOCOUNT cuando necesites resultados de la fila afectada. Para un ejemplo completo, véase Track each result in a batch.
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())
El constructor de marca temporal requiere un argumento de microsegundos
Si Timestamp(year, month, day, hour, minute, second) lanza TypeError por la falta del argumento microsecond, mejora mssql-python. El controlador actual acepta el constructor DB-API de seis argumentos y establece microsecond en cero por defecto. Para más información, consulte DB-API constructor de marcas de tiempo.
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
La copia masiva falla tras una actualización de paquete
Si las consultas normales funcionan pero bulkcopy() o bulkcopy_arrow() no importa o carga el módulo nativo de copia masiva, actualiza el controlador con dependencias:
python -m pip install --upgrade mssql-python
python -m pip check
El controlador requiere un entorno de ejecución mssql-python-rs equivalente. Una actualización parcial o una instalación con --no-deps puede dejar paquetes incompatibles instalados. Si usas un índice de paquetes privado, replica ambos paquetes complementarios y conserva los pines de dependencia declarados por el driver. Para los pins actuales, consulta Requisitos de dependencia.
Nombres de destino no soportados
bulkcopy() y bulkcopy_arrow() aceptan como máximo tres partes identificadoras. Un nombre de cuatro partes como server.database.schema.table provoca RuntimeError durante la consulta de metadatos antes de que se envíe ninguna fila. Conéctate directamente al servidor de destino y utiliza un nombre de tabla de una, dos o tres partes. Para escapes de corchetes y errores de nombres malformados, véase Nombres de las tablas objetivo.
Unicode o segundos fraccionados perdidos durante la copia masiva
Actualiza el controlador si la copia masiva corrompe el texto UTF-8 o trunca las fracciones de segundo al cargar valores datetime2 compatibles. El tiempo de ejecución de copia masiva actual gestiona el texto UTF-8 y preserva la precisión de datetime2 disponible en los tipos de origen y destino.
Usa nvarchar o una colación UTF-8 en varchar para el texto Unicode. Los valores de Python datetime y los métodos fetch de Arrow del controlador están limitados a microsegundos. Para valores de 100 nanosegundos ya almacenados en una columna de marca de tiempo de nanosegundos de Arrow, carga en datetime2(7) sin convertir primero a Python datetime. Para más información, véase Unicode y precisión temporal y precisión temporal de Arrow.
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, cargue los datos en una tabla de almacenamiento provisional y luego combínelos 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) eleva 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,
)