Ескертпе
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Жүйеге кіруді немесе каталогтарды өзгертуді байқап көруге болады.
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Каталогтарды өзгертуді байқап көруге болады.
Драйвер 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']}")