Recuperar dados com mssql-python

O driver mssql-python oferece vários métodos de busca, padrões de acesso a linhas e recursos de navegação por cursor para recuperar resultados de consulta.

Métodos de obtenção

Após executar uma consulta SELECT, use métodos de busca para recuperar os resultados.

Fetchone()

Retorna uma única linha ou None , se não houver mais linhas disponíveis:

cursor.execute("SELECT ProductID, Name, ListPrice FROM Production.Product")

row = cursor.fetchone()
while row:
    print(f"{row.ProductID}: {row.Name} - ${row.ListPrice}")
    row = cursor.fetchone()

fetchmany()

Retorna uma lista de linhas. cursor.arraysize Controla o tamanho padrão do lote (padrão: 1):

cursor.execute("SELECT * FROM Production.Product")
cursor.arraysize = 100  # Fetch 100 rows at a time

while True:
    rows = cursor.fetchmany()
    if not rows:
        break
    for row in rows:
        print(row.Name)

Você também pode especificar o tamanho diretamente:

rows = cursor.fetchmany(50)  # Fetch up to 50 rows

fetchall()

Retorna todas as linhas restantes como uma lista:

cursor.execute("SELECT * FROM Production.Product WHERE Color = 'Black'")
rows = cursor.fetchall()

print(f"Found {len(rows)} products")
for row in rows:
    print(row.Name)

Fetchval()

Retorna a primeira coluna da primeira linha, o que é útil para consultas escalares.

count = cursor.execute("SELECT COUNT(*) FROM Production.Product").fetchval()
print(f"Total products: {count}")

max_price = cursor.execute("SELECT MAX(ListPrice) FROM Production.Product").fetchval()
print(f"Highest price: ${max_price}")

Padrões de acesso a linhas

A Row classe suporta múltiplos padrões de acesso.

Acesso ao índice

Acesse as colunas por posição (baseado em zero):

cursor.execute("SELECT ProductID, Name, ListPrice FROM Production.Product WHERE ProductID < 5")
row = cursor.fetchone()

product_id = row[0]
name = row[1]
price = row[2]

Acesso a atributos

Acesse as colunas pelo nome:

cursor.execute("SELECT ProductID, Name, ListPrice FROM Production.Product WHERE ProductID < 5")
row = cursor.fetchone()

product_id = row.ProductID
name = row.Name
price = row.ListPrice

Converter nomes de colunas em minúsculas

Ative nomes de atributos minúsculos globalmente:

import mssql_python

settings = mssql_python.get_settings()
settings.lowercase = True

cursor.execute("SELECT ProductID, Name FROM Production.Product WHERE ProductID < 5")
row = cursor.fetchone()
print(row.productid, row.name)  # Lowercase access
settings.lowercase = False  # Restore default

Iteração

As linhas suportam iteração sobre valores:

cursor.execute("SELECT ProductID, Name, ListPrice FROM Production.Product WHERE ProductID < 5")
row = cursor.fetchone()

for value in row:
    print(value)

Iteração do cursor

Itere diretamente sobre o cursor para processar as linhas:

cursor.execute("SELECT * FROM Production.Product")

for row in cursor:
    print(row.Name)

Esse padrão equivale a chamar fetchone() repetidamente.

Metadados de colunas

Acesse informações da coluna por meio de cursor.description:

cursor.execute("SELECT ProductID, Name, ListPrice FROM Production.Product WHERE ProductID < 5")

for col in cursor.description:
    name, type_code, display_size, internal_size, precision, scale, null_ok = col
    print(f"Column: {name}, Type: {type_code}, Nullable: {null_ok}")

Contagem de linhas

O cursor.rowcount atributo indica:

  • Para SELECT: Retorna -1 após execute() até o início da busca. Assim que você começa a recuperar os dados, isso reflete o número cumulativo de linhas recuperadas até o momento.
  • Para INSERT/UPDATE/DELETE: Número de linhas afetadas.
cursor.execute("SELECT * FROM Production.Product")
print(f"Rows returned: {cursor.rowcount}")

cursor.execute("CREATE TABLE #PriceUpd (Name NVARCHAR(50), Price DECIMAL(10,2), CategoryID INT)")
cursor.execute("INSERT INTO #PriceUpd VALUES ('A',10,1),('B',20,1),('C',30,2)")
cursor.execute("UPDATE #PriceUpd SET Price = Price * 1.1 WHERE CategoryID = 1")
print(f"Rows updated: {cursor.rowcount}")

Navegação por cursor

skip()

Pule as fileiras sem buscá-las:

cursor.execute("SELECT * FROM Production.Product ORDER BY ProductID")
cursor.skip(10)  # Skip first 10 rows
row = cursor.fetchone()  # Returns 11th row

scroll()

Mova a posição do cursor para frente:

cursor.execute("SELECT * FROM Production.Product ORDER BY ProductID")

# Move forward 5 rows from current position
cursor.scroll(5, mode='relative')

row = cursor.fetchone()

Note

O driver suporta apenas mode='relative' com valores positivos. O posicionamento absoluto e a rolagem para trás geram NotSupportedError porque o driver usa cursores apenas para frente.

Número da linha

Acompanhe a posição atual:

cursor.execute("SELECT * FROM Production.Product")

print(f"Initial position: {cursor.rownumber}")  # -1 (before first fetch)

row = cursor.fetchone()
print(f"After fetchone: {cursor.rownumber}")    # 0 (first row fetched)

Vários conjuntos de resultados

nextset() Use para processar múltiplos conjuntos de resultados:

cursor.execute("""
    SELECT * FROM Production.Product WHERE Color = 'Black';
    SELECT * FROM Production.ProductCategory;
    SELECT COUNT(*) FROM Production.Product;
""")

# First result set
products = cursor.fetchall()
print(f"Products: {len(products)}")

# Move to second result set
if cursor.nextset():
    categories = cursor.fetchall()
    print(f"Categories: {len(categories)}")

# Move to third result set
if cursor.nextset():
    count = cursor.fetchval()
    print(f"Total count: {count}")

Grandes conjuntos de resultados

Para conjuntos de resultados grandes, processe linhas em lotes para gerenciar a memória:

def process_batch(rows):
    # Example: print each row. Replace with your own logic.
    for row in rows:
        print(row)

cursor.execute("SELECT * FROM LargeTable")
cursor.arraysize = 1000

while True:
    rows = cursor.fetchmany()
    if not rows:
        break

    process_batch(rows)
    print(f"Processed {cursor.rownumber} rows so far")

Gerenciadores de contexto

Use gerentes de contexto para limpeza automática de recursos:

with mssql_python.connect(connection_string) as conn:
    with conn.cursor() as cursor:
        cursor.execute("SELECT * FROM Production.Product")
        for row in cursor:
            print(row.Name)
# Cursor and connection closed automatically

Práticas recomendadas

  • Use fetchmany() para resultados grandes para evitar carregar tudo na memória.
  • Feche os cursores quando isso é feito para liberar recursos do servidor.
  • Use nomes de colunas (acesso a atributos) para um código mais legível.
  • Confere rowcount Após as instruções de modificação de dados.
  • Trate explicitamente os valores None quando as colunas podem ser nulas.