Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
mssql-python-drivrutinen returnerar raddata som Row objekt från hämtaoperationer. Dessa objekt erbjuder flexibla åtkomstmönster:
-
Attributåtkomst (
row.ColumnName) är det mest läsbara valet för namngivna kolumner. Använd den när din fråga har en känd, stabil kolumnlista. -
Strängnyckelåtkomst (
row['ColumnName']) ger lexikonliknande åtkomst till kolumner efter namn, användbart när du behöver programmatisk kolumnuppslagning eller när kolumnnamn innehåller mellanslag eller specialtecken. -
Indexåtkomst (
row[0]) är användbar för dynamiska frågor där kolumnnamn inte är kända vid utvecklingstillfället, eller vid bearbetningSELECT *av resultat. -
Tuple unpacking (
a, b, c = row) är det mest koncisa valet för loopkroppar med ett litet, fast antal kolumner. -
Mapping access (
row._mapping) returnerar en skrivskyddad mappning av kolumnnamn till värden. Använd den för att konvertera en rad till en ordbok eller för att skicka raden till kod som förväntar sig en mappning.
Attributåtkomst
Åtkomst till kolumnvärden direkt efter namn:
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
Skiftlägesberoende
Åtkomst till kolumnnamn är kasuskänslig och matchar kolumnnamnen som returneras av SQL Server. Om din databas använder inkonsekvent casing, använd SQL-aliaser AS för att normalisera namn, eller aktivera modulinställningen lowercase (se Modulkonfiguration):
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
Kolumnaliaser
Använd SQL-alias för att skapa vänliga attributnamn:
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})")
Indexåtkomst
Åtkomstvärden efter nollbaserat kolumnindex:
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
Negativ indexering
Drivrutinen stödjer negativ indexering i Python-stil:
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)
Strängnyckelåtkomst
Åtkomst till kolumnvärden efter namn med hjälp av ordboksliknande syntax:
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')
Detta är användbart när kolumnnamn innehåller mellanslag eller specialtecken, eller när du behöver komma åt kolumner programmatiskt:
column_name = 'ListPrice'
value = row[column_name] # Programmatic column access
Skivning
Extrahera flera värden med hjälp av skivor:
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-uppackning
Packa upp radvärden direkt till variabler:
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}")
Delvis upppackning
Använd * för att fånga återstående värden:
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}")
Radlängd och iteration
Arbeta med raddimensioner och iterera genom kolumnvärden:
Få kolumnräkning
Använd len() för att få antalet kolumner i rad:
cursor.execute("SELECT * FROM Production.Product WHERE ProductID < 5")
row = cursor.fetchone()
print(len(row)) # Number of columns
Iterera över värden
Loop genom kolumnvärden i ordning:
cursor.execute("SELECT ProductID, Name, ListPrice FROM Production.Product WHERE ProductID < 5")
row = cursor.fetchone()
for value in row:
print(value)
Kontrollera om kolumnen finns
Använd hasattr() för att testa förekomsten av ett kolumnnamn:
# Use hasattr to check for column name
if hasattr(row, 'DiscountPrice'):
print(f"Discount: {row.DiscountPrice}")
else:
print("No discount available")
Konvertera till inbyggda typer
Radobjekt kan konverteras till standardtyper i Python för integration med andra bibliotek och API:er:
Konvertera till tupel
Konvertera en rad till en tuple med konstruktorn tuple() :
cursor.execute("SELECT ProductID, Name FROM Production.Product WHERE ProductID = 1")
row = cursor.fetchone()
row_tuple = tuple(row)
print(row_tuple) # (1, 'Adjustable Race')
Konvertera till lista
Konvertera en rad till en lista med konstruktören list() :
row_list = list(row)
print(row_list) # [1, 'Adjustable Race']
Konvertera till ordlista
Konvertera en rad till en ordbok när du behöver serialisera den till JSON, skicka den till en mallmotor eller slå ihop den med annan data. Egenskapen row._mapping returnerar en skrivskyddad mappning av kolumnnamn till värden i resultatuppsättningens kolumnordning. Skicka den till dict() för att få en vanlig ordbok:
cursor.execute("SELECT ProductID, Name, ListPrice FROM Production.Product WHERE ProductID = 1")
row = cursor.fetchone()
row_dict = dict(row._mapping)
print(row_dict) # {'ProductID': 1, 'Name': 'Adjustable Race', 'ListPrice': Decimal('0.0000')}
Egenskapen _mapping har dessa beteenden:
- Mappningen är skrivskyddad. Att tilldela en nyckel höjer
TypeError. Konvertera det meddict()först om du behöver ändra värden. - Nycklar är kolumnnamnen från
cursor.description. Nyckeluppslagen är kasuskänsliga. Om du aktiverarlowercasemodulinställningen är tangenterna gemener, och mappningen matchar bara de gemener tangenterna. Attribut- och strängnyckelåtkomst på raden blir kasuskänslig närlowercaseden är på, menrow._mappinguppslagen gör det inte. - Om resultatuppsättningen har dubblettkolumnnamn behåller mappningen det sista värdet för varje namn. Använd Transact-SQL (T-SQL)
ASalias för att ge varje kolumn ett unikt namn, eller läs värdena efter index. - Egenskapen har företräde framför en resultatkolumn med namnet
_mapping, sårow._mappingden returnerar alltid avbildningen. Läs den kolumnen medrow['_mapping'].
Hjälpfunktion för diktomvandling
Skapa en återanvändbar hjälpfunktion för att konvertera alla hämtade rader till ordböcker:
def rows_to_dicts(cursor):
"""Convert fetched rows to list of dictionaries."""
return [dict(row._mapping) 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'])
Arbete med nullbara värden
Drivrutinen returnerar NULL-värden som PythonNone:
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}"
Arbeta med cursor.description
Åtkomst till kolumnmetadata tillsammans med raddata:
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]}")
Vanliga mönster
Här är praktiska mönster för att arbeta med radobjekt i verkliga tillämpningar:
Processrader med namngiven åtkomst
Processrader med attributåtkomst för läsbar, underhållbar kod:
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}")
Bygg objekt från rader
För applikationer med en domänmodell, mappa rader till dataklasser eller typade objekt. Denna mappning ger dig IDE-autokomplettering, typkontroll och en tydlig gräns mellan databasrader och applikationslogik.
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
]
Export till JSON
Serialisera radobjekt till JSON med anpassad typhantering för datetime och decimalvärden:
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):
rows = [dict(row._mapping) 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")
Aggregera i grupper
Gruppera rader efter ett kolumnvärde och samla dem i en ordbok för analys eller visning:
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']}")