أول دالة: CREATE FUNCTION
دالة محفوظة في قاعدة البيانات تستقبل قيمًا وتُرجع نتيجة، وتستدعيها من أي استعلام. ⏱ نحو 40 دقيقة.
- تنشئ دالة بمعاملات ونوع إرجاع بـ
CREATE FUNCTION. - تكتب جسم الدالة بـ
plpgsqlأوsql. - تستدعي الدالة داخل
SELECTعلى كل صف. - تعدّل الدالة بـ
CREATE OR REPLACEوتحذفها بـDROP FUNCTION.
١من كتلة مؤقتة إلى دالة محفوظة
كتلة DO تُنفّذ مرة وتختفي. أما الدالة Function فتُحفظ في قاعدة البيانات باسم، وتستقبل معاملات، وتُرجع قيمة، ويستدعيها أي استعلام أو تطبيق في أي وقت.
CREATE FUNCTION price_with_vat(p numeric)RETURNS numericLANGUAGE plpgsqlAS $$BEGIN RETURN round(p * 1.15, 2);END;$$; SELECT name, price, price_with_vat(price) AS بعد_الضريبةFROM products WHERE category_id = 1;
| name | price | بعد_الضريبة |
|---|---|---|
| حاسب محمول | 3200 | 3680 |
| جهاز لوحي | 1450 | 1667.5 |
| شاشة 27 بوصة | 980 | 1127 |
الدالة تُستدعى داخل SELECT كأي دالة جاهزة مثل round، وتعمل على كل صف.
| الجزء | معناه |
|---|---|
CREATE FUNCTION price_with_vat(p numeric) | اسم الدالة ومعاملها p ونوعه |
RETURNS numeric | نوع القيمة التي تُرجعها |
LANGUAGE plpgsql | لغة جسم الدالة |
AS $$ … $$ | جسم الدالة: كتلة BEGIN … END |
RETURN …; | يُنهي الدالة ويُرجع القيمة |
٢دالة تقرأ من الجداول
جسم الدالة كتلة كاملة: فيها متغيرات و SELECT INTO وشروط. هذه دالة تُرجع عدد طلبات عميل:
CREATE FUNCTION order_count(cid int)RETURNS intLANGUAGE plpgsqlAS $$DECLARE n int;BEGIN SELECT count(*) INTO n FROM orders WHERE customer_id = cid; RETURN n;END;$$; SELECT id, name, order_count(id) AS الطلباتFROM customers ORDER BY الطلبات DESC, id LIMIT 4;
| id | name | الطلبات |
|---|---|---|
| 1 | سارة | 3 |
| 2 | خالد | 2 |
| 3 | نورة | 2 |
| 4 | فهد | 2 |
وإن كان جسم الدالة استعلامًا واحدًا فقط، فالأبسط أن تكتبها بلغة sql بلا BEGIN و END:
CREATE FUNCTION customer_city(cid int) RETURNS textLANGUAGE sqlAS $$ SELECT city FROM customers WHERE id = cid;$$; SELECT customer_city(4);
| customer_city |
|---|
| الدمام |
٣التعديل والحذف
إنشاء دالة بالاسم نفسه مرتين يعطي خطأ. لتعديلها استخدم CREATE OR REPLACE FUNCTION، ولحذفها DROP FUNCTION مع أنواع معاملاتها:
CREATE FUNCTION price_with_vat(p numeric)RETURNS numericLANGUAGE plpgsqlAS $$BEGIN RETURN round(p * 1.15, 2);END;$$;CREATE FUNCTION price_with_vat(p numeric)RETURNS numericLANGUAGE plpgsqlAS $$BEGIN RETURN round(p * 1.20, 2);END;$$;
CREATE OR REPLACE FUNCTION price_with_vat(p numeric)RETURNS numericLANGUAGE plpgsqlAS $$BEGIN RETURN round(p * 1.15, 2);END;$$;CREATE OR REPLACE FUNCTION price_with_vat(p numeric)RETURNS numericLANGUAGE plpgsqlAS $$BEGIN RETURN round(p * 1.20, 2);END;$$;SELECT price_with_vat(100);
| price_with_vat |
|---|
| 120 |
في PostgreSQL قد توجد دالتان بالاسم نفسه إذا اختلفت أنواع معاملاتهما (التحميل الزائد Overloading)، لذلك نكتب الأنواع عند الحذف: DROP FUNCTION price_with_vat(numeric);
لاحظ في Oracle: RETURN بدل RETURNS، وIS بدل AS $$، وتنتهي بشرطة مائلة / في أداة SQL Developer.
توقّع وتحقّق
ما الفرق الأساسي بين DO والدالة؟
أين تُستدعى الدالة غالبًا؟
لتعديل دالة موجودة دون حذفها نكتب:
متى نكتب الدالة بـ LANGUAGE sql؟
الخلاصة
- الدالة: اسم ومعاملات و
RETURNSنوع، وجسم ينتهي بـRETURN. - تُستدعى داخل الاستعلامات:
SELECT f(col) FROM t. - جسم من استعلام واحد ←
LANGUAGE sqlبلاBEGIN. CREATE OR REPLACEللتعديل، وDROP FUNCTION f(الأنواع)للحذف.- سمِّ المعاملات بأسماء لا تطابق الأعمدة.
تحدٍّ برمجي: إجمالي الطلب
متوسطاكتب دالة order_total(oid int) تُرجع إجمالي طلب: مجموع الكمية × سعر الوحدة لكل بنوده.
- الدالة تُرجع
numeric. - تجمع
qty * unit_priceمنorder_itemsلهذا الطلب. - الطلب الذي لا بنود له يُرجع 0 لا NULL (استخدم
coalesce).
👀 اعرض الناتج المطلوب
- الكود يعمل بلا أخطاء
- الطلب 1 إجماليه 3350
- الطلب 8 إجماليه 210
- طلب غير موجود ← 0
- تعمل على كل الطلبات داخل SELECT
💡 تلميح 1
💡 تلميح 2
coalesce(sum(qty * unit_price), 0) تُرجع 0 إن لم توجد بنود.حاول بنفسك أولًا؛ للمسألة أكثر من حلّ صحيح.
CREATE OR REPLACE FUNCTION order_total(oid int)RETURNS numericLANGUAGE plpgsqlAS $$DECLARE t numeric;BEGIN SELECT coalesce(sum(qty * unit_price), 0) INTO t FROM order_items WHERE order_id = oid; RETURN t;END;$$;