Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Драйвер mssql-python возвращает строки в виде Row объектов из операций выборки. Эти объекты обеспечивают гибкие паттерны доступа:
-
Доступ к атрибуту (
row.ColumnName) — самый читаемый выбор для именованных столбцов. Используйте его, когда в вашем запросе есть известный и стабильный список столбцов. -
Доступ к строковому ключу (
row['ColumnName']) обеспечивает словарный доступ к столбцам по названию, что полезно при программном поиске столбцов или когда имена столбцов содержат пробелы или специальные символы. -
Доступ к индексу (
row[0]) полезен для динамических запросов, где имена столбцов неизвестны на момент разработки или при обработкеSELECT *результатов. -
Распаковка кортежей (
a, b, c = row) — самый лаконичный выбор для корпусов петель с небольшим фиксированным количеством столбцов.
Доступ к атрибутам
Доступ к значениям столбцов напрямую по названию:
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
Учет регистра
Доступ к именам столбцов чувствителен к регистру и совпадает с названиями столбцов, возвращаемых SQL Server. Если ваша база данных использует несогласованный корпус, используйте SQL-псевдонимы AS для нормализации имён или включите lowercase настройки модуля (см. конфигурацию модуля):
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
Псевдонимы колонок
Используйте SQL-псевдонимы для создания дружественных имён атрибутов:
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})")
Доступ к индексу
Значения доступа по индексу столбцов на основе нуля:
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
Отрицательная индексация
Драйвер поддерживает отрицательную индексацию в стиле Python:
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)
Доступ к строковому ключу
Доступ к значениям столбцов по названию с помощью синтаксиса словарного стиля:
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')
Это полезно, когда в названиях столбцов есть пробелы или специальные символы, или когда нужно программно получить доступ к столбцам:
column_name = 'ListPrice'
value = row[column_name] # Programmatic column access
Нарезка
Извлекайте несколько значений с помощью срезов:
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
Распаковка кортежей
Распаковывайте значения строк напрямую в переменные:
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}")
Частичная распаковка
Используйте * для захвата оставшихся значений:
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}")
Длина строки и итерация
Работайте с размерностями строк и просматривайте значения столбцов:
Получите количество столбцов
Используйте len() для получения количества столбцов в строке:
cursor.execute("SELECT * FROM Production.Product WHERE ProductID < 5")
row = cursor.fetchone()
print(len(row)) # Number of columns
Итерация по значениям
Проведите значения столбцов по порядку:
cursor.execute("SELECT ProductID, Name, ListPrice FROM Production.Product WHERE ProductID < 5")
row = cursor.fetchone()
for value in row:
print(value)
Проверьте, существует ли столбец
Используйте hasattr() для проверки наличия названия столбца:
# Use hasattr to check for column name
if hasattr(row, 'DiscountPrice'):
print(f"Discount: {row.DiscountPrice}")
else:
print("No discount available")
Конвертация в встроенные типы
Объекты строк можно преобразовать в стандартные типы Python для интеграции с другими библиотеками и API:
Преобразование в кортеж
Преобразуем строку в кортеж с помощью 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')
Преобразовать в список
Преобразуйте строку в список с помощью list() конструктора:
row_list = list(row)
print(row_list) # [1, 'Adjustable Race']
Конвертировать в словарь
Преобразуйте строку в словарь, когда нужно сериализировать её в JSON, передайте в шаблонный движок или объедините с другими данными. Постройте словарь из cursor.description и значений строк:
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')}
Вспомогательная функция для преобразования диктовки
Создайте многократно используемую вспомогательную функцию для преобразования всех полученных строк в словари:
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'])
Работа с обнулируемыми значениями
Драйвер возвращает значения NULL в формате Python None:
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
Доступ к метаданным столбцов вместе с данными строк:
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]}")
Распространенные шаблоны
Вот практические шаблоны работы с объектами Row в реальных приложениях:
Строки процессов с именованным доступом
Обработка строк с использованием доступа к атрибутам для читаемого, поддерживаемого кода:
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}")
Строить объекты из строк
Для приложений с доменной моделью сопоставьте строки с классами данных или типизированными объектами. Это отображение даёт автозаполнение IDE, проверку типов и чёткую границу между строками базы данных и логикой приложения.
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
Сериализуйте объекты строк в JSON с помощью пользовательской обработки типов для значений datetime и десятичных:
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")
Объединение в группы
Сгруппируйте строки по значению столбца и соберите их в словарь для анализа или отображения:
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']}")