Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Use este artigo para diagnosticar problemas de execução de consultas, tipo de dados, desempenho, transação e cópia em massa com o mssql-python driver.
Problemas de execução de consultas
Tabela ou objeto não encontrado
Sintomas:
ProgrammingError: [42S02] (208) Invalid object name 'TableName'.
Possíveis causas e soluções:
Contexto incorreto da base de dados
cursor.execute("SELECT DB_NAME()") print(cursor.fetchone()[0])Esquema não especificado
cursor.execute("SELECT * FROM dbo.TableName")A tabela não existe
cursor.execute(""" SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'TableName' """)
Erro de sintaxe
Sintomas:
ProgrammingError: [42000] (102) Incorrect syntax near '...'.
Soluções:
Teste a instrução SQL no SQL Server Management Studio (SSMS) para verificar a sintaxe.
Use uma consulta parametrizada em vez de interpolação de strings:
# 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}, )
Erros de parâmetros
Sintomas:
ProgrammingError: [07001] Wrong number of parameters
Soluções:
Conte os marcadores de posição e os parâmetros. As contagens devem corresponder.
Escolha o estilo de parâmetros correto:
# 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())
Contagens de linhas incorretas em lotes com múltiplos resultados
Se rowcount repetir a contagem da primeira instrução após nextset(), atualize o driver. Cada atualização bem-sucedida nextset() atualiza a contagem para o novo resultado. Um resultado que produz uma linha começa em -1 antes da obtenção. Verifique cursor.description antes de buscar porque os resultados de modificação de dados contêm contagens em vez de linhas.
Deixe SET NOCOUNT de lado quando precisar de resultados das linhas afetadas. Para um exemplo completo, veja Acompanhar cada resultado num lote.
Problemas de tipo de dados
Erros de conversão de data e hora
Sintomas:
DataError: [22007] Invalid datetime format
Solution:
Use objetos Python datetime em vez de strings.
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())
O construtor de timestamp requer um argumento de microssegundo
Se Timestamp(year, month, day, hour, minute, second) gerar TypeError por falta do argumento microsecond, atualize-se mssql-python. O driver atual aceita o construtor DB-API de seis argumentos e define microsecond como zero por predefinição. Para mais informações, consulte DB-API construtor de carimbo temporal.
Questões de precisão decimal
Sintomas:
Os números parecem truncados ou arredondados incorretamente.
Solution:
Utilização 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 codificação Unicode
Sintomas:
Caracteres especiais aparecem distorcidos ou causam erros.
Soluções:
Use colunas nvarchar para dados Unicode na sua base de dados.
Passe as cadeias de caracteres diretamente. O driver trata da codificação:
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 desempenho
Execução lenta da consulta
Possíveis causas e soluções:
Índices em falta: Verifique o plano de execução da consulta no SSMS.
Grandes conjuntos de resultados: Usar
fetchmany()em vez defetchall():cursor.arraysize = 1000 while True: rows = cursor.fetchmany() if not rows: break process_rows(rows)Agrupamento de ligações desativado: Ativar agrupamento:
import mssql_python mssql_python.pooling(max_size=20, idle_timeout=300)
Problemas de memória com resultados de grande dimensão
Sintomas:
O processo Python fica sem memória.
Soluções:
Transmita os resultados em fluxo em vez de carregar todas as linhas para a memória.
cursor.execute("SELECT * FROM LargeTable") for row in cursor: process_row(row)Use paginação do lado do 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
Questões de transação
Âmbito da tabela temporária com autocommit
As tabelas temporárias de sessão (#tablename) criadas dentro de uma transação desaparecem quando a transação é revertida. Este comportamento costuma causar confusão quando o autocommit está desligado, que é o padrão:
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 logo após criares uma tabela temporária, ou usa o modo de confirmação automática:
cursor.execute("CREATE TABLE #TempData (ID INT, Name NVARCHAR(50))")
conn.commit()
cursor.execute("INSERT INTO #TempData VALUES (1, 'test')")
conn.commit()
As instruções DDL que exigem modo de autocommit, como CREATE DATABASE, falham dentro de uma transação aberta. Defina o autocommit antes de os executar:
conn.autocommit = True
cursor.execute("CREATE DATABASE TestDB")
conn.autocommit = False
Transação não comprometida
Sintomas:
As alterações nos dados não persistem depois de fechar a ligação.
Solution:
Com autocommit=False, que é a predefinição, chame commit():
cursor.execute("CREATE TABLE #Products (Name NVARCHAR(100))")
cursor.execute(
"INSERT INTO #Products (Name) VALUES (%(name)s)",
{"name": "Widget"},
)
conn.commit()
Alternativamente, use o modo de autocommit:
conn = mssql_python.connect(connection_string, autocommit=True)
Erros de bloqueio
Sintomas:
OperationalError: [40001] (1205) Transaction ... was deadlocked on lock resources with another process
Solution:
A lógica de repetição lida com a falha imediata, mas bloqueios recorrentes indicam um problema de conceção. Capture o grafo de impasse e analise as instruções e os tipos de bloqueio. As correções mais comuns incluem estas alterações:
- Reordene as operações para que as transações concorrentes adquiram bloqueios na mesma sequência.
- Reduzir o âmbito das transações.
- Adicione índices apropriados para reduzir a duração do bloqueio.
Para uma explicação detalhada da análise de deadlocks, consulte o guia sobre Deadlocks. Se usar o Base de Dados SQL do Azure, veja Analisar e prevenir bloqueios.
Problemas de carregamento em massa
Cópia em massa falha após uma atualização de pacote
Se as consultas normais funcionarem, mas bulkcopy() ou bulkcopy_arrow() não conseguir importar ou carregar o módulo nativo de cópia em massa, atualize o controlador com dependências:
python -m pip install --upgrade mssql-python
python -m pip check
O controlador requer um runtime correspondente mssql-python-rs. Uma atualização parcial ou uma instalação com --no-deps pode deixar pacotes incompatíveis instalados. Se usar um índice de pacotes privado, espelhe ambos os pacotes companheiros e preserve as restrições de dependência declaradas pelo controlador. Para as versões fixadas atuais, veja Requisitos de Dependência.
Nomes de destinos não suportados
bulkcopy() e bulkcopy_arrow() aceitam no máximo três partes identificadoras. Um nome em quatro partes, como server.database.schema.table, gera RuntimeError durante a consulta de metadados antes de quaisquer linhas serem enviadas. Ligue-se diretamente ao servidor de destino e use um nome de tabela de uma, duas ou três partes. Para escapes de colchetes e erros de nomes malformados, veja Nomes da tabela de destino.
Unicode ou segundos fracionados perdidos durante a cópia em massa
Atualize o driver se a cópia em massa corromper o texto UTF-8 ou truncar frações de segundo ao carregar valores datetime2 compatíveis. O runtime atual de cópia em massa lida com texto UTF-8 e preserva a precisão datetime2 disponível nos tipos de origem e destino.
Use nvarchar ou uma colação UTF-8 no varchar para texto Unicode. Os valores de Python datetime e os métodos Arrow fetch do driver estão limitados a microssegundos. Para valores de 100 nanossegundos já mantidos numa coluna timestamp de nanossegundos do Arrow, carregue em datetime2(7) sem converter primeiro para Pythondatetime. Para mais informações, veja Unicode e precisão temporal e precisão temporal do Arrow.
Violação de restrições durante a cópia em massa
Sintomas:
RuntimeError: CHECK constraint ... Conflict occurred in database ...
RuntimeError: Cannot insert duplicate key ... violation of PRIMARY KEY constraint
Causa:
Os dados no lote violam restrições da tabela, como restrições de chave primária, unicidade, verificação ou chave estrangeira.
Solution:
Valida os dados antes de os carregares. Para grandes conjuntos de dados, carregue os dados numa tabela de preparação e, em seguida, intercale-os no 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 padrões de upsert com tabelas de preparação, consulte Padrões de carregamento e movimentação de dados.
Erros de mapeamento de colunas
Sintomas:
RuntimeError: Bulk copy failure - column count mismatch
Causa:
O número de colunas nos seus dados não corresponde ao número alvo de colunas da tabela, ou as colunas estão na ordem errada.
Solution:
Certifique-se de que os seus dados correspondam ao esquema da tabela na ordem e no número:
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 a cópia em massa
Sintomas:
Os dados carregam, mas os valores estão truncados, arredondados ou incorretos.
Causa:
Os valores de Python não correspondem de forma clara aos tipos de coluna de destino. Exemplos comuns incluem float valores carregados em colunas decimais , que podem perder precisão, e strings sobredimensionadas carregadas em colunas de comprimento fixo.
Solution:
Usa tipos em Python que correspondam ao teu 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)
Falhas de ligação do tipo NumPy
Sintomas:
Os parâmetros falham silenciosamente ou geram erros de tipo de dados ao utilizar tipos inteiros ou de vírgula flutuante do NumPy.
Causa:
Tipos NumPy como numpy.int64 e numpy.int32 não passam isinstance(x, int) no NumPy 2.x. A inferência de tipo do condutor não os reconhece, o que causa comportamentos inesperados.
Solution:
Converta valores do NumPy para tipos nativos de Python antes de os atribuir:
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 dados maiores, use os caminhos de integração Arrow ou pandas . Estes caminhos tratam da conversão de tipos internamente.
Cópia em massa com tabelas temporárias
Sintomas:
cursor.bulkcopy("#TempTable", data) aumenta RuntimeError: Invalid object name '#TempTable'.
Causa:
bulkcopy() Não é possível resolver tabelas temporárias de sessão (#tablename) devido a limitações na consulta de metadados. As tabelas temporárias globais (##tablename) e as tabelas permanentes funcionam.
Solution:
Use uma tabela temporária global ou uma tabela de preparação regular:
# 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 dados pequenos onde prefere uma tabela temporária de sessão, use executemany():
cursor.execute("CREATE TABLE #Staging (ID INT, Name NVARCHAR(50))")
cursor.executemany(
"INSERT INTO #Staging (ID, Name) VALUES (?, ?)",
rows,
)