Ескертпе
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Жүйеге кіруді немесе каталогтарды өзгертуді байқап көруге болады.
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Каталогтарды өзгертуді байқап көруге болады.
Драйвер mssql-python предоставляет курсорные методы для выполнения SQL-запросов, параметризованных запросов, пакетных операций и подготовленных операторов.
Базовое выполнение запроса
Используйте метод execute() курсора для выполнения инструкций SQL:
import mssql_python
conn = mssql_python.connect(connection_string)
cursor = conn.cursor()
cursor.execute("SELECT Name, ListPrice FROM Production.Product WHERE Color = 'Black'")
rows = cursor.fetchall()
for row in rows:
print(row.Name, row.ListPrice)
cursor.close()
conn.close()
Параметризованные запросы
Всегда используйте параметризованные запросы, чтобы предотвратить внедрение SQL. Стиль параметров драйвера по умолчанию — pyformat (именованные заполнители), но он также поддерживает qmark (позиционные заполнители). Используйте qmark для экранирующих последовательностей ODBC {CALL}.
Стиль Pyformat (по умолчанию)
Используйте именованные заполнители с синтаксисом %(name)s и передайте словарь:
cursor.execute(
"SELECT Name, ListPrice FROM Production.Product WHERE Color = %(color)s AND ListPrice > %(price)s",
{"color": "Black", "price": 10.00}
)
Стиль Qmark
Используйте позиционные заполнители с ? и передайте кортеж или список:
cursor.execute(
"SELECT Name, ListPrice FROM Production.Product WHERE ProductSubcategoryID = ? AND ListPrice > ?",
(1, 10.00)
)
Драйвер автоматически определяет стиль параметров на основе вашего SQL-запроса и типов параметров.
INSERT, UPDATE, DELETE операции
Для операторов модификации данных используйте параметризованные запросы и зафиксируйте транзакцию:
cursor.execute("CREATE TABLE #ExecDemo (Name NVARCHAR(50), CategoryID INT, Price DECIMAL(10,2))")
cursor.execute(
"INSERT INTO #ExecDemo (Name, CategoryID, Price) VALUES (%(name)s, %(category)s, %(price)s)",
{"name": "New Product", "category": 1, "price": 19.99}
)
conn.commit()
print(f"Rows affected: {cursor.rowcount}")
Пакетное выполнение с помощью executemany()
Используйте executemany() для эффективной вставки нескольких строк. Драйвер использует привязку параметров по столбцам для обеспечения высокой производительности:
products = [
{"name": "Product A", "category": 1, "price": 10.00},
{"name": "Product B", "category": 1, "price": 15.00},
{"name": "Product C", "category": 2, "price": 20.00},
]
cursor.execute("CREATE TABLE #BatchDemo (Name NVARCHAR(50), CategoryID INT, Price DECIMAL(10,2))")
cursor.executemany(
"INSERT INTO #BatchDemo (Name, CategoryID, Price) VALUES (%(name)s, %(category)s, %(price)s)",
products
)
conn.commit()
print(f"Rows inserted: {cursor.rowcount}")
С использованием стиля qmark:
products = [
("Product A", 1, 10.00),
("Product B", 1, 15.00),
("Product C", 2, 20.00),
]
cursor.execute("CREATE TABLE #QmarkDemo (Name NVARCHAR(50), CategoryID INT, Price DECIMAL(10,2))")
cursor.executemany(
"INSERT INTO #QmarkDemo (Name, CategoryID, Price) VALUES (?, ?, ?)",
products
)
conn.commit()
Многокомпонентное пакетное выполнение
Используйте batch_execute() для подключения, чтобы выполнить несколько разных инструкций за один вызов:
results, cursor = conn.batch_execute(
[
"CREATE TABLE #BatchExec (Name NVARCHAR(50), CategoryID INT)",
"INSERT INTO #BatchExec (Name, CategoryID) VALUES (%(name)s, %(cat)s)",
"SELECT COUNT(*) FROM #BatchExec"
],
[
None, # No params for CREATE
{"name": "New Item", "cat": 1}, # Params for INSERT
None # No params for SELECT
]
)
print(f"CREATE result: {results[0]}")
print(f"INSERT affected: {results[1]} rows")
print(f"Row count: {results[2][0][0]}")
Подготовленные выражения
Драйвер по умолчанию готовит запросы (use_prepare=True). Когда вы выполняете одну и ту же SQL-строку несколько раз с использованием одного и того же курсора, драйвер автоматически повторно использует подготовленное выражение при последующих вызовах:
# First execution prepares the statement
cursor.execute(
"SELECT Name, ListPrice FROM Production.Product WHERE ProductSubcategoryID = %(subcategory_id)s",
{"subcategory_id": 1},
)
rows1 = cursor.fetchall()
# Same SQL string on same cursor → driver reuses the prepared plan
cursor.execute(
"SELECT Name, ListPrice FROM Production.Product WHERE ProductSubcategoryID = %(subcategory_id)s",
{"subcategory_id": 2},
)
rows2 = cursor.fetchall()
Чтобы пропустить подготовку и использовать прямое исполнение:
cursor.execute(
"SELECT Name, ListPrice FROM Production.Product WHERE ProductSubcategoryID = 1",
use_prepare=False # Uses SQLExecDirectW instead of SQLPrepareW
)
Выполнение на уровне соединения
Для простых единичных запросов используйте execute() напрямую на соединение:
# Creates cursor, executes, and returns cursor
cursor = conn.execute("SELECT TOP 10 Name, ListPrice FROM Production.Product")
rows = cursor.fetchall()
cursor.close()
Хранимые процедуры
Вызывайте хранимые процедуры с помощью EXECUTE или управляющей последовательности ODBC {CALL}. Для получения информации о выходных параметрах, нескольких наборах результатов и паттернах транзакций см. раздел «Хранимые процедуры».
cursor.execute(
"EXECUTE dbo.uspGetManagerEmployees @BusinessEntityID = %(business_entity_id)s",
{"business_entity_id": 16}
)
rows = cursor.fetchall()
Задайте размеры входов
Используйте setinputsizes() для явного объявления типов параметров, что может повысить производительность пакетных операций:
cursor.setinputsizes([
(mssql_python.SQL_WVARCHAR, 50, 0), # NVARCHAR(50)
(mssql_python.SQL_INTEGER, 0, 0), # INT
])
cursor.executemany(
"SELECT ProductID, Name FROM Production.Product WHERE Name LIKE ? AND ProductSubcategoryID = ?",
[("Road%", 2), ("Mountain%", 1)]
)
Замечание
Не все константы типов SQL работают с setinputsizes().
SQL_WVARCHAR и SQL_INTEGER надёжны. Для десятичных значений используйте автоматический вывод типа драйвера вместо SQL_DECIMAL, который имеет известную проблему (GitHub #503).
Обработка ошибок
Оберните операции с базой данных в блоки try-except:
try:
cursor.execute("CREATE TABLE #ErrDemo (Name NVARCHAR(50) NOT NULL)")
cursor.execute("INSERT INTO #ErrDemo (Name) VALUES (%(name)s)", {"name": None})
conn.commit()
except mssql_python.IntegrityError as e:
print(f"Constraint violation: {e}")
conn.rollback()
except mssql_python.ProgrammingError as e:
print(f"SQL error: {e}")
conn.rollback()
Лучшие практики
- Всегда используйте параметризованные запросы , чтобы предотвратить инъекцию SQL.
-
Используйте пакетное копирование для пакетной вставки данных вместо нескольких вызовов
execute(). - Обязательно фиксируйте транзакции при отключении автокоммита.
- Закрывайте курсоры и соединения при освобождении ресурсов.
- Используйте менеджеры контекста для автоматической очистки ресурсов:
with mssql_python.connect(connection_string) as conn:
with conn.cursor() as cursor:
cursor.execute("SELECT TOP 5 Name, ListPrice FROM Production.Product")
rows = cursor.fetchall()
# Connection and cursor automatically closed