إنشاء دوال ذات قيمة جدول
تسمح الدوال ذات القيم الجداولية بتغليف منطق الاستعلام المعقد في مكونات قابلة لإعادة الاستخدام تعيد مجموعات النتائج. يمكنك استدعاء هذه الدوال مباشرة في الاستعلامات، تماما مثل الجداول أو العروض، مما يجعل كودك أكثر مرونة وقابلية للصيانة.
عند بناء تطبيقات قواعد البيانات، غالبا ما تحتاج إلى استرجاع مجموعات بيانات مفلترة أو محسوبة بناء على معلمات الإدخال. تحل الدوال ذات القيمة الجداول هذه المشكلة عن طريق تغليف منطق الاستعلام في دوال تقبل المعاملات وجداول الإرجاع. على عكس الإجراءات المخزنة، يمكنك استخدام الدوال ذات القيمة الجداول في JOIN الجمل والعبارات SELECT ، مما يمنحك المرونة في اعتبار نتائج الدوال مصادر بيانات.
فهم أنواع الدوال ذات القيم الجداول
يوفر SQL Server نوعين من الدوال ذات القيمة الجداولية، كل منهما مناسب لسيناريوهات مختلفة.
الدالة ذات القيم الجدول المضمنة
يحتوي على بيان واحد SELECT ويعيد النتائج مباشرة. مع الدوال الداخلية، لا تحدد هيكل الجدول — بل SQL Server يستنتجها من جملتك SELECT . يعامل محسن الاستعلامات الدوال ذات القيم الجداول الداخلية كعروض مع معاملات، وغالبا ما ينتج خطط تنفيذ أفضل.
دالة ذات قيم جدولية متعددة العبارات
يستخدم كتلة BEGIN...END ويعلن صراحة هيكل الجدول المرتجع. هذا النوع يمنحك مزيدا من التحكم عندما تحتاج إلى تنفيذ عدة عبارات، أو إجراء حسابات معقدة، أو بناء مجموعة النتائج بشكل تكراري. ومع ذلك، تأتي هذه المرونة مع توازن في الأداء، حيث يتعامل المحسن مع هذه الوظائف بشكل مختلف.
الاختيار بين هاتين الوظيفتين يعتمد على متطلباتك الخاصة. بالنسبة للاستعلامات البسيطة ذات المعلمات، توفر الدوال المتداخلة أداء أفضل. عندما تحتاج إلى منطق إجرائي أو خطوات متعددة لبناء مجموعة النتائج، تصبح وظائف متعددة العبارات ضرورية.
إنشاء دوال ذات قيم جدول ضمن
توفر الدوال ذات القيم الجداولية المضمنة طريقة موجزة لتحويل الاستعلامات إلى معلمات. تعرفها بعبارة RETURN واحدة تليها استعلام SELECT.
المثال التالي يوضح دالة داخلية تسترجع الطلبات لعميل معين:
CREATE FUNCTION dbo.GetCustomerOrders
(
@CustomerID INT
)
RETURNS TABLE
AS
RETURN
(
SELECT
OrderID,
OrderDate,
TotalAmount,
Status
FROM Sales.Orders
WHERE CustomerID = @CustomerID
);
يمكنك الآن استخدام هذه الدالة في الاستعلامات تماما مثل الجدول:
SELECT OrderID, OrderDate, TotalAmount
FROM dbo.GetCustomerOrders(1001)
WHERE OrderDate >= '2024-01-01';
تقبل الدالة معامل معرف العميل وتعيد فقط طلبات ذلك العميل. يمكنك تصفية النتائج بشكل إضافي، JOINأو تجميعها حسب الحاجة. هذا النهج يحافظ على نظافة استفسارك الرئيسي مع تغليف منطق تصفية العميل.
إنشاء دوال ذات قيمة جدول متعددة العبارات
توفر الدوال ذات القيم الجداولية متعددة العبارات مرونة أكبر عندما تحتاج إلى تنفيذ عمليات متعددة لبناء مجموعة نتائجك.
اعتبر دالة تحسب ملخصات مبيعات المنتجات باستخدام عدة تجميعات:
CREATE FUNCTION dbo.GetProductSalesSummary
(
@StartDate DATE,
@EndDate DATE
)
RETURNS @SalesSummary TABLE
(
ProductID INT,
ProductName NVARCHAR(100),
TotalQuantity INT,
TotalRevenue DECIMAL(18,2),
AveragePrice DECIMAL(18,2)
)
AS
BEGIN
INSERT INTO @SalesSummary
SELECT
p.ProductID,
p.ProductName,
SUM(od.Quantity) AS TotalQuantity,
SUM(od.Quantity * od.UnitPrice) AS TotalRevenue,
AVG(od.UnitPrice) AS AveragePrice
FROM Production.Products p
INNER JOIN Sales.OrderDetails od ON p.ProductID = od.ProductID
INNER JOIN Sales.Orders o ON od.OrderID = o.OrderID
WHERE o.OrderDate BETWEEN @StartDate AND @EndDate
GROUP BY p.ProductID, p.ProductName;
RETURN;
END;
لاحظ كيف تعلن صراحة عن متغير @SalesSummary الجدول مع أعمدة وأنواع بيانات محددة. يقوم جسم الدالة بإدخال البيانات في هذا المتغير الجدولي، ثم يعيدها. تسمح لك هذه البنية بإضافة منطق معالجة إضافي، أو معالجة الأخطاء، أو عبارات شرطية حسب الحاجة.
استخدم الدوال ذات القيم الجداول في الاستعلامات
تندمج الدوال ذات القيمة الجداول بسلاسة في استفساراتك، مما يمكن أنماط استرجاع بيانات قوية.
يمكنك ربط نتائج الدوال بجداول أخرى:
SELECT
c.CustomerName,
s.ProductName,
s.TotalRevenue
FROM Customers c
CROSS APPLY dbo.GetProductSalesSummary('2024-01-01', '2024-12-31') s
WHERE s.TotalRevenue > 10000
ORDER BY s.TotalRevenue DESC;
CROSS APPLY يستدعي المشغل الدالة لكل صف من جدول العملاء، رغم أن معلمات الدوال في هذا المثال هي ثوبت. عندما تمرر قيم الأعمدة كمعلمات، CROSS APPLY يصبح ذلك مفيدا بشكل خاص:
SELECT
c.CustomerName,
o.OrderID,
o.TotalAmount
FROM Customers c
CROSS APPLY dbo.GetCustomerOrders(c.CustomerID) o
WHERE o.Status = 'Completed';
يسترجع هذا الاستعلام جميع الطلبات المكتملة لكل عميل، موضحا كيف تمكن الوظائف ذات القيمة الجداول المعالجة صفا بصف داخل استفساراتك. تعمل الدالة كاستعلام فرعي مرتبط ولكن مع سهولة قراءة وإعادة استخدام أفضل.
بالنسبة للدوال ذات القيم الجداول المضمنة التي لا تتطلب تقييما صفا بصف، يمكنك استخدام INNER JOIN النحو أيضا:
SELECT
c.CustomerName,
o.OrderDate,
o.TotalAmount
FROM Customers c
INNER JOIN dbo.GetCustomerOrders(c.CustomerID) o ON 1=1
WHERE YEAR(o.OrderDate) = 2024;
مع هذه التقنيات، يمكنك بناء استعلامات معقدة من مكونات وظائف أبسط ومختبرة، مما يحسن من سهولة صيانة الكود وكفاءة التطوير.