mssql-python'da satır nesneleri

mssql-python sürücüsü, satır verilerini Row fetch işlemlerinden nesne olarak döndürür. Bu nesneler esnek erişim kalıpları sağlar:

  • Özellik erişimi (row.ColumnName) isimli sütunlar için en okunabilir seçenektir. Sorunuz bilinen, kararlı bir sütun listesine sahipse kullanın.
  • Dizi anahtarı erişimi (row['ColumnName']), sütunlara isimle sözlük tarzı erişim sağlar; bu, programatik sütun araması gerektiğinde veya sütun adlarında boşluklar veya özel karakterler olduğunda faydalıdır.
  • Index erişimi (row[0]), geliştirme sırasında sütun adlarının bilinmediği dinamik sorgular veya sonuçlar işlenirken SELECT * faydalıdır.
  • Tuple unpacking (a, b, c = row) küçük ve sabit sayıda sütuna sahip loop gövdeleri için en özlü seçimdir.

Öznitelik erişimi

Sütun değerlerine doğrudan isimle erişin:

import mssql_python

conn = mssql_python.connect(connection_string)
cursor = conn.cursor()

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

print(row.ProductID)     # 1
print(row.Name)          # 'Adjustable Race'
print(row.ListPrice)     # 0.00

Büyük/küçük harfe duyarlı

Sütun adı erişimi büyük harf duyarlıdır ve SQL Server tarafından gönderilen sütun adlarıyla eşleşir. Veritabanınız tutarsız kaplan kullanıyorsa, isimleri normalleştirmek için SQL AS takma adları kullanın veya modül ayarını lowercase etkinleştirin ( bkz. Modül yapılandırması):

cursor.execute("SELECT FirstName, LastName, EmailPromotion FROM Person.Person WHERE BusinessEntityID < 10")
row = cursor.fetchone()

print(row.FirstName)      # Works
print(row.LastName)       # Works
print(row.EmailPromotion) # Works
print(row.firstname)      # AttributeError - wrong case

Sütun takma adları

Dost öznitelik adları oluşturmak için SQL aliasları kullanın:

cursor.execute("""
    SELECT 
        p.ProductID,
        p.Name,
        c.Name AS Category
    FROM Production.Product p
    JOIN Production.ProductSubcategory c ON p.ProductSubcategoryID = c.ProductSubcategoryID
    WHERE p.ProductSubcategoryID IS NOT NULL
""")

for row in cursor:
    print(f"{row.Name} ({row.Category})")

Indeks erişimi

Sıfır tabanlı sütun indeksi ile değerlere erişin:

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

print(row[0])  # ProductID
print(row[1])  # Name
print(row[2])  # ListPrice

Negatif indeksleme

Sürücü, Python tarzı negatif indeksleme desteğini destekler:

cursor.execute("""
    SELECT Demo.A, Demo.B, Demo.C, Demo.D
    FROM (VALUES (1, 2, 3, 4)) AS Demo(A, B, C, D)
""")
row = cursor.fetchone()

print(row[-1])  # Last column (D)
print(row[-2])  # Second to last (C)

Dize anahtarı erişimi

Sütun değerlerine sözlük tarzı sözdizimi kullanılarak isme göre erişin:

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

print(row['ProductID'])   # 1
print(row['Name'])        # 'Adjustable Race'
print(row['ListPrice'])   # Decimal('0.00')

Bu, sütun adlarında boşluklar veya özel karakterler içerdiğinde veya sütunlara programatik olarak erişmeniz gerektiğinde faydalıdır:

column_name = 'ListPrice'
value = row[column_name]  # Programmatic column access

Dilimleme

Dilimler kullanarak birden fazla değer çıkarın:

cursor.execute("""
    SELECT Demo.A, Demo.B, Demo.C, Demo.D, Demo.E
    FROM (VALUES (1, 2, 3, 4, 5)) AS Demo(A, B, C, D, E)
""")
row = cursor.fetchone()

print(row[1:4])    # Columns B, C, D (indices 1, 2, 3)
print(row[:2])     # First two columns (A, B)
print(row[2:])     # From C to end

Tuple açılma

Satır değerlerini doğrudan değişkenlere açın:

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

for product_id, name, price in cursor:
    print(f"#{product_id}: {name} - ${price}")

Kısmi açılma

Kalan değerleri yakalamak için kullanılır * :

cursor.execute("""
    SELECT TOP 2 ProductID, Name, ProductNumber, Color, Size, Weight
    FROM Production.Product
    WHERE ProductNumber IS NOT NULL
    ORDER BY ProductID
""")

for product_id, name, *rest in cursor:
    print(f"{product_id}: {name}, extra columns: {rest}")

Satır uzunluğu ve yineleme

Satır boyutlarıyla çalışın ve sütun değerlerinde tekrarlayın:

Sütun sayısını alın

Sıradaki sütun sayısını almak için kullanılır len() :

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

print(len(row))  # Number of columns

Değerler üzerinde yineleme

Sütun değerlerini şu sırayla döngüye alın:

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

for value in row:
    print(value)

Sütunun var olup olmadığını kontrol edin

Bir sütun adının varlığını test etmek için kullanılır hasattr() :

# Use hasattr to check for column name
if hasattr(row, 'DiscountPrice'):
    print(f"Discount: {row.DiscountPrice}")
else:
    print("No discount available")

Yerleşik tiplere dönüştürün

Sıra nesneleri, diğer kütüphaneler ve API'lerle entegrasyon için standart Python tiplerine dönüştürülebilir:

Tuple'a dönüştürün

Bir satırı yapıcıyla tuple() tuple'a dönüştürün:

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

row_tuple = tuple(row)
print(row_tuple)  # (1, 'Adjustable Race')

Listeye dönüştür

Bir satırı yapıcı list() kullanarak bir listeye dönüştürün:

row_list = list(row)
print(row_list)  # [1, 'Adjustable Race']

Sözlüğe dönüştür

Bir satırı JSON'a serileştirmek gerekirken, bir şablon motoruna aktarmak veya başka verilerle birleştirmek gerekirse sözlüğe dönüştürün. Sözlüğü ve cursor.description satır değerlerinden oluşturun:

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

# Create dict from description and values
columns = [col[0] for col in cursor.description]
row_dict = dict(zip(columns, row))
print(row_dict)  # {'ProductID': 1, 'Name': 'Adjustable Race', 'ListPrice': Decimal('0.00')}

Dikt dönüşümü için yardımcı fonksiyon

Tüm getirilen satırları sözlüklere dönüştürmek için yeniden kullanılabilir bir yardımcı fonksiyon oluşturun:

def rows_to_dicts(cursor):
    """Convert fetched rows to list of dictionaries."""
    columns = [col[0] for col in cursor.description]
    return [dict(zip(columns, row)) for row in cursor.fetchall()]

cursor.execute("SELECT ProductID, Name, ListPrice FROM Production.Product WHERE ProductID < 10")
products = rows_to_dicts(cursor)
for p in products:
    print(p['Name'])

Nullable değerlerle çalışma

Sürücü, NULL değerleri Python Noneolarak döndürür:

cursor.execute("SELECT FirstName, MiddleName, LastName FROM Person.Person WHERE BusinessEntityID = 1")
row = cursor.fetchone()

if row.MiddleName is None:
    full_name = f"{row.FirstName} {row.LastName}"
else:
    full_name = f"{row.FirstName} {row.MiddleName} {row.LastName}"

Cursor.description ile çalışma

Sütun meta verilerine satır verileriyle birlikte erişin:

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

# Column information
for col in cursor.description:
    print(f"Name: {col[0]}, Type: {col[1]}")

# Fetch with metadata
row = cursor.fetchone()
for i, col in enumerate(cursor.description):
    print(f"{col[0]}: {row[i]}")

Ortak desenler

İşte gerçek dünya uygulamalarında Row nesneleriyle çalışmak için pratik kalıplar:

İsimli erişime sahip işlem satırları

Okunabilir ve sürdürülebilir kod için öznitelik erişimi kullanan satırlar işlemek:

def process_orders(conn):
    cursor = conn.cursor()
    cursor.execute("""
        SELECT SalesOrderID, CustomerID, OrderDate, TotalDue 
        FROM Sales.SalesOrderHeader 
        WHERE Status = 5
    """)
    
    for order in cursor:
        print(f"Order #{order.SalesOrderID}")
        print(f"  Customer: {order.CustomerID}")
        print(f"  Date: {order.OrderDate}")
        print(f"  Total: ${order.TotalDue:.2f}")

Satırlardan nesneler oluşturun

Alan modeli olan uygulamalar için, satırlar veri sınıflarına veya tiplenen nesnelere eşlenir. Bu eşleme, IDE otomatik tamamlama, tür kontrolü ve veritabanı satırları ile uygulama mantığı arasında net bir sınır sağlar.

from dataclasses import dataclass
from datetime import date
from decimal import Decimal

@dataclass
class Product:
    id: int
    name: str
    price: Decimal
    created: date

def get_products(conn) -> list[Product]:
    cursor = conn.cursor()
    cursor.execute("SELECT ProductID, Name, ListPrice, SellStartDate FROM Production.Product WHERE ProductID < 10")
    
    return [
        Product(
            id=row.ProductID,
            name=row.Name,
            price=row.ListPrice,
            created=row.SellStartDate
        )
        for row in cursor
    ]

JSON'a ihracat

Date time ve Denimal değerler için özel tür işleme ile Row Nesnelerini JSON'a serileyin:

import json
from datetime import date, datetime
from decimal import Decimal

def json_serializer(obj):
    """Custom serializer for non-JSON types."""
    if isinstance(obj, (date, datetime)):
        return obj.isoformat()
    if isinstance(obj, Decimal):
        return float(obj)
    raise TypeError(f"Type {type(obj)} not serializable")

def export_to_json(cursor, filename):
    columns = [col[0] for col in cursor.description]
    rows = [dict(zip(columns, row)) for row in cursor.fetchall()]
    
    with open(filename, 'w') as f:
        json.dump(rows, f, default=json_serializer, indent=2)

cursor.execute("SELECT ProductID, Name, ListPrice FROM Production.Product WHERE ProductID < 10")
export_to_json(cursor, "products.json")

Gruplara toplanma

Satırları bir sütun değerine göre gruplayın ve analiz veya görüntüleme için bir sözlükte toplayın:

from collections import defaultdict

cursor.execute("""
    SELECT c.Name AS CategoryName, p.Name AS ProductName, p.ListPrice 
    FROM Production.Product p
    JOIN Production.ProductSubcategory c ON p.ProductSubcategoryID = c.ProductSubcategoryID
    WHERE p.ProductSubcategoryID IS NOT NULL
    ORDER BY c.Name
""")

products_by_category = defaultdict(list)
for row in cursor:
    products_by_category[row.CategoryName].append({
        'name': row.ProductName,
        'price': row.ListPrice
    })

for category, products in products_by_category.items():
    print(f"\n{category}:")
    for p in products:
        print(f"  - {p['name']}: ${p['price']}")