Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
mssql-python sürücüsü, DB-API 2.0 spesifikasyonundan bu callproc() yöntemi uygulamaz.
callproc() çağrılması NotSupportedError yükseltir. Bunun yerine, standart sorgu yürütme yöntemleriyle ODBC {CALL ...} kaçış dizisini kullanın.
Temel kayıtlı prosedür yürütme
Parametresiz
Escape dizisini kullanarak {CALL} bir saklanan prosedürü çalıştırın. Bu örnek, parametre almayan ve veritabanı başına bir satır döndüren sp_databases sistem saklı yordamını çağırır:
import mssql_python
conn = mssql_python.connect(connection_string)
cursor = conn.cursor()
cursor.execute("{CALL sp_databases}")
for row in cursor:
print(row.DATABASE_NAME, row.DATABASE_SIZE)
Giriş parametreleriyle
Parametreleri konumsal veya adlandırılmış yer tutucular kullanarak geçirin:
# Single parameter
cursor.execute(
"{CALL dbo.uspGetManagerEmployees(?)}", (16,)
)
for row in cursor:
print(row.FirstName, row.LastName)
Çıkış parametreleri
Çıkış parametrelerini bildir ve geri getir
SQL Server depolanmış prosedürleri, çıktı parametreleri aracılığıyla değerleri döndürebilir. Çıktı değerlerini yakalamak için Transact-SQL (T-SQL) değişkenleri kullanın, ardından bunları bir SELECT ifadeyle alın:
cursor.execute("""
DECLARE @total_out MONEY;
SELECT @total_out = SUM(TotalDue)
FROM Sales.SalesOrderHeader
WHERE CustomerID = %(customer_id)s;
SELECT @total_out AS TotalAmount;
""", {"customer_id": 29825})
row = cursor.fetchone()
total = row.TotalAmount
print(f"Customer total: ${total}")
Çoklu çıkış parametreleri
Ayrı değişkenler ilan ederek birden fazla çıktı değerini yakalayın. Aynı desen, parametreleri OUTPUT olan herhangi bir depolanmış prosedürde de çalışır:
cursor.execute("""
DECLARE @total_orders INT, @total_spent MONEY;
SELECT @total_orders = COUNT(*), @total_spent = SUM(TotalDue)
FROM Sales.SalesOrderHeader
WHERE CustomerID = %(cust_id)s;
SELECT @total_orders AS OrderCount, @total_spent AS TotalSpent;
""", {"cust_id": 29825})
stats = cursor.fetchone()
print(f"Orders: {stats.OrderCount}, Total spent: ${stats.TotalSpent}")
Dönüş değerleri
Saklanan prosedür dönüş değerini yakalayın
Sonuçları geri getiren bir kayıtlı prosedür çalıştırın:
cursor.execute("EXECUTE dbo.uspGetEmployeeManagers @BusinessEntityID = %(emp_id)s", {"emp_id": 5})
rows = cursor.fetchall()
if rows:
print(f"Found {len(rows)} managers in chain")
for row in rows:
print(f" Manager: {row.FirstName} {row.LastName}")
else:
print("No managers found")
Çıkış parametreleriyle dönüş değeri
cursor.execute("""
DECLARE @return_value INT, @message NVARCHAR(500);
SELECT @return_value = CASE WHEN COUNT(*) > 0 THEN 0 ELSE 1 END,
@message = CASE WHEN COUNT(*) > 0 THEN N'Customer found' ELSE N'Customer not found' END
FROM Sales.Customer WHERE CustomerID = %(cust_id)s;
SELECT @return_value AS ReturnCode, @message AS Message;
""", {"cust_id": 29825})
result = cursor.fetchone()
print(f"Return code: {result.ReturnCode}, Message: {result.Message}")
Sonuç kümeleri
Tek sonuç kümesi
Tek bir sonuç kümesi döndüren bir saklanan prosedürü çalıştırın:
cursor.execute(
"{CALL dbo.uspGetBillOfMaterials(?, ?)}",
(800, "2026-01-01")
)
customers = cursor.fetchall()
for row in customers:
print(f"{row.ProductAssemblyID}: {row.ComponentDesc}")
Birden fazla sonuç kümesi
Bazı saklı yordamlar birden çok sonuç kümesi döndürür. Bunlar arasında gezinmek için kullanın nextset() :
cursor.execute("""
SELECT TOP 1 SalesOrderID, OrderDate, TotalDue
FROM Sales.SalesOrderHeader WHERE CustomerID = 29825;
SELECT TOP 3 Name, ListPrice
FROM Production.Product WHERE ListPrice > 0
ORDER BY ListPrice DESC;
""")
# First result set: order header
order = cursor.fetchone()
print(f"Order: {order.SalesOrderID}, Date: {order.OrderDate}")
cursor.nextset()
# Second result set: products
print("Products:")
for item in cursor:
print(f" {item.Name}: ${item.ListPrice}")
Daha fazla sonuç seti için kontrol edin
Saklanan bir prosedür tarafından geri dönen tüm sonuç kümelerini şu şekilde nextset()yinele:
cursor.execute("SELECT TOP 3 ProductID, Name FROM Production.Product; SELECT TOP 3 FirstName, LastName FROM Person.Person")
result_set_num = 1
while True:
print(f"--- Result Set {result_set_num} ---")
for row in cursor:
print(row)
if not cursor.nextset():
break
result_set_num += 1
Depolanmış prosedürlerle işlemler
Açık işlem kontrolü
Atomikliği sağlamak için birden fazla depolanmış prosedür çağrısını bir işlem içine alın:
conn.autocommit = False
try:
cursor.execute("{CALL dbo.DebitAccount(?, ?)}", (1001, 100.00))
cursor.execute("{CALL dbo.CreditAccount(?, ?)}", (1002, 100.00))
conn.commit()
print("Transfer completed")
except mssql_python.DatabaseError as e:
conn.rollback()
print(f"Transfer failed: {e}")
Saklanan prosedürün işlemi yönetmesine izin verin
Eğer saklanan prosedür kendi işlemlerini yönetiyorsa:
conn.autocommit = True # Let SP manage transactions
cursor.execute("""
DECLARE @result INT;
EXECUTE @result = dbo.TransferFunds
@FromAccount = %(from_acc)s,
@ToAccount = %(to_acc)s,
@Amount = %(amount)s;
SELECT @result AS TransferResult;
""", {"from_acc": 1001, "to_acc": 1002, "amount": 100.00})
result = cursor.fetchone()
if result.TransferResult == 0:
print("Transfer successful")
Hata yönetimi
Saklanan prosedür hatalarını yakalayın
Depolanmış prosedürler veya Transact-SQL ifadeleri tarafından ortaya çıkan istisnaları yönetin:
try:
cursor.execute("{CALL dbo.DangerousProcedure}")
except mssql_python.ProgrammingError as e:
# Handle SQL errors raised by RAISERROR or THROW
print(f"Stored procedure error: {e}")
except mssql_python.DatabaseError as e:
# Handle other database errors
print(f"Database error: {e}")
PRINT ifadeleri ve bilgilendirici mesajları yakalayın
SQL Server PRINT deyimleri ve önem derecesi 11'in altında olan RAISERROR yürütmeden sonra cursor.messages içinde yakalanır. Her giriş bir (message_type, message_text) tuple'dır. Bir PRINT, sonuç kümesinden önce çalıştığında kendine ait, satır içermeyen bir sonuç kümesi oluşturur; bu nedenle önce cursor.messages öğesini okuyun, ardından satırlara ulaşmak için nextset() çağrısını yapın:
cursor.execute("PRINT 'Operation complete'; SELECT 1 AS Status")
for msg_type, msg_text in cursor.messages:
print(f"Server message: {msg_text}")
cursor.nextset()
row = cursor.fetchone()
print(f"Status: {row.Status}")
Bir saklı yordam, birden çok sonuç kümesi genelinde PRINT mesajları ürettiğinde, her sonuç kümesindeki mesajların yakalanmasını sağlamak için execute() sonrasında ve her nextset() çağrısından sonra yeniden cursor.messages okuyun:
cursor.execute("""
PRINT 'Starting first result set';
SELECT TOP 3 ProductID, Name FROM Production.Product;
PRINT 'Starting second result set';
SELECT TOP 3 FirstName, LastName FROM Person.Person;
""")
all_messages = []
while True:
all_messages.extend(cursor.messages)
if cursor.description:
for row in cursor:
print(row)
if not cursor.nextset():
break
for _, text in all_messages:
print(f"Server: {text}")
Tam cursor.messages API için bkz. İmleç yönetimi.
En iyi uygulamalar
Adlandırılmış parametreleri kullanın
Adlandırılmış parametreler daha açıktır ve sıra bağımsızlığı sağlar:
# Recommended: {CALL} with positional parameters
cursor.execute(
"{CALL dbo.uspGetBillOfMaterials(?, ?)}",
(800, "2026-01-01")
)
# Also valid: EXECUTE with named T-SQL parameters
cursor.execute("""
EXECUTE dbo.uspGetBillOfMaterials
@StartProductID = ?,
@CheckDate = ?
""", (800, "2026-01-01"))
Null atanabilir çıkış parametrelerini işleme
Depolanmış prosedürlerden çıktı parametreleri alınırken NULL değerleri kontrol edin:
cursor.execute("""
DECLARE @optional_value NVARCHAR(100);
SELECT @optional_value = Color FROM Production.Product WHERE ProductID = %(id)s;
SELECT @optional_value AS OutputValue;
""", {"id": 1})
result = cursor.fetchone()
if result.OutputValue is not None:
print(f"Value: {result.OutputValue}")
else:
print("No value returned")
Saklı yordamlarda SET NOCOUNT ON kullanın
Daha iyi performans ve daha temiz sonuç yönetimi için, depolanmış prosedürlerinizin şunları içerdiğinden emin olun:
CREATE PROCEDURE dbo.MyProcedure
AS
BEGIN
SET NOCOUNT ON; -- Prevents "n rows affected" messages
-- procedure logic
END
Örnek: Tam iş akışı
İşte bir saklanan prosedürü çağıran, çıktı değerlerini alan ve hataları yöneten pratik bir örnek:
import mssql_python
def get_employee_report(manager_id: int) -> dict:
"""Look up a manager's employees and compute average vacation hours."""
conn = mssql_python.connect(connection_string)
conn.autocommit = False
cursor = conn.cursor()
try:
# Get manager info
cursor.execute("""
SELECT BusinessEntityID, JobTitle
FROM HumanResources.Employee
WHERE BusinessEntityID = %(mgr)s
""", {"mgr": manager_id})
mgr = cursor.fetchone()
print(f"Manager {mgr.BusinessEntityID}: {mgr.JobTitle}")
# Get direct reports via stored procedure
cursor.execute("{CALL dbo.uspGetManagerEmployees(?)}", (manager_id,))
employees = cursor.fetchall()
print(f"Found {len(employees)} employee(s)")
# Compute average vacation hours
cursor.execute("""
DECLARE @avg_hours INT;
SELECT @avg_hours = AVG(VacationHours)
FROM HumanResources.Employee;
SELECT @avg_hours AS AvgVacation;
""")
avg = cursor.fetchone().AvgVacation
print(f"Avg vacation hours: {avg}")
conn.commit()
return {"manager": mgr.JobTitle, "reports": len(employees), "avg_vacation": avg}
except mssql_python.DatabaseError as e:
conn.rollback()
raise
finally:
cursor.close()
conn.close()
# Usage
result = get_employee_report(manager_id=16)
OUTPUT INSERTED kullanarak oluşturulan anahtarları alın
INSERT öğesinden bir kimlik değeri almak için (saklı yordamla veya saklı yordam olmadan), SCOPE_IDENTITY() yerine OUTPUT INSERTED kullanın. Bu yaklaşım, aynı sonuç kümesinde değeri döndürür:
cursor.execute("""
INSERT INTO Production.ProductCategory (Name)
OUTPUT INSERTED.ProductCategoryID
VALUES (%(name)s)
""", {"name": "Custom Parts"})
new_id = cursor.fetchval()
print(f"New category ID: {new_id}")
Bu desen, kimlik sütunu olan herhangi bir tablo için çalışır ve bir işlem kaydedilemez.
Desteklenmeyen özellikler
callproc()
mssql-python çağırırsanız sürücü NotSupportedError oluştururcursor.callproc(). Bunun yerine, bu makale boyunca gösterildiği gibi cursor.execute("{CALL ...}") veya cursor.execute("EXECUTE ...") kullanın.
Tablo değerine sahip parametreler (TVP'ler)
Tablo değerli parametreler, mssql-python’nin mevcut sürümünde (1.11.0) desteklenmez. Bir satır setini bir dosyalanan prosedüre aktarmanız gerekiyorsa, alternatifler kullanın:
- Önce geçici bir tabloya ekle, sonra saklanan prosedürü oradan okun.
- Verileri bir aşamalama tablosuna yüklemek için kullanılır
bulkcopy(). - Bir JSON dizesi geçirin ve bunu prosedür içinde
OPENJSONile ayrıştırın.