طَبِّقْهاتعلّم المبدأ، وطبّقه بيدكمقرر 122 · برمجة قواعد البيانات
الدرس 17 · الوحدة 8: إنشاء إجراءات مخزنة

معاملات الإجراء: IN و OUT و INOUT

الإجراء لا يُرجع قيمة، لكنه يُخرج ما تريد عبر معاملاته. ⏱ نحو 35 دقيقة.

بعد هذا الدرس ستستطيع أن:
  • تفرّق بين معاملات IN و OUT و INOUT.
  • تستدعي إجراءً بمعاملات OUT وتستقبل مخرجاته في متغيرات.
  • تستخدم القيم الافتراضية وتسمية المعاملات عند الاستدعاء.
  • تكتب دالة بمعاملات OUT تُرجع صفًّا.

١ثلاثة اتجاهات للمعامل

الاتجاهالبياناتمثال
IN (الافتراضي)تدخل إلى الإجراء فقطرقم العميل
OUTتخرج من الإجراء فقطعدد طلباته
INOUTتدخل بقيمة، وتخرج بقيمة جديدةمبلغ يدخل ويخرج بعد الخصم
query.sql
CREATE PROCEDURE customer_stats(  IN  cid    int,  OUT n_orders int,  OUT spent    numeric)LANGUAGE plpgsqlAS $$BEGIN  SELECT count(DISTINCT o.id), coalesce(sum(i.qty * i.unit_price), 0)  INTO n_orders, spent  FROM orders o LEFT JOIN order_items i ON i.order_id = o.id  WHERE o.customer_id = cid;END;$$; CALL customer_stats(1, NULL, NULL);
✓ أُنشئ الإجراء المخزن
النتيجة · صف واحد
n_ordersspent
33805

عند الاستدعاء بـ CALL نضع NULL مكان كل معامل OUT، فيُرجع الإجراء صفًّا بقيمها.

٢استقبال المخرجات في متغيرات

داخل كتلة أو إجراء آخر نمرّر متغيرات مكان معاملات OUT، فتمتلئ بعد الاستدعاء:

query.sql
CREATE PROCEDURE customer_stats(  IN  cid    int,  OUT n_orders int,  OUT spent    numeric)LANGUAGE plpgsqlAS $$BEGIN  SELECT count(DISTINCT o.id), coalesce(sum(i.qty * i.unit_price), 0)  INTO n_orders, spent  FROM orders o LEFT JOIN order_items i ON i.order_id = o.id  WHERE o.customer_id = cid;END;$$; DO $$DECLARE  n int;  s numeric;BEGIN  CALL customer_stats(3, n, s);  RAISE NOTICE 'نورة: % طلبات بمجموع % ريال', n, s;END $$;
✓ أُنشئ الإجراء المخزن
NOTICE: نورة: 2 طلبات بمجموع 3530.00 ريال
✓ نُفّذت الكتلة

ومعامل INOUT يدخل بقيمة ويعود بأخرى:

query.sql
CREATE PROCEDURE apply_discount(INOUT amount numeric, IN pct numeric DEFAULT 10)LANGUAGE plpgsqlAS $$BEGIN  amount := round(amount * (1 - pct / 100), 2);END;$$; DO $$DECLARE  bill numeric := 500;BEGIN  CALL apply_discount(bill);              -- pct أخذ القيمة الافتراضية 10  RAISE NOTICE 'بعد الخصم الافتراضي: %', bill;  CALL apply_discount(bill, pct => 20);   -- تسمية المعامل عند الاستدعاء  RAISE NOTICE 'بعد خصم 20%% إضافي: %', bill;END $$;
✓ أُنشئ الإجراء المخزن
NOTICE: بعد الخصم الافتراضي: 450.00
NOTICE: بعد خصم 20% إضافي: 360.00
✓ نُفّذت الكتلة

DEFAULT يجعل المعامل اختياريًّا، وpct => 20 يسمّي المعامل فلا يهم ترتيبه. و%% داخل RAISE تطبع علامة % نفسها.

٣الدالة بمعاملات OUT

الدالة أيضًا تقبل OUT، فتُرجع صفًّا بعدة أعمدة دون تعريف نوع خاص:

query.sql
CREATE FUNCTION price_range(cat int, OUT low numeric, OUT high numeric)LANGUAGE sqlAS $$ SELECT min(price), max(price) FROM products WHERE category_id = cat $$; SELECT c.name, r.low, r.highFROM categories c, price_range(c.id) rORDER BY c.id;
✓ أُنشئت الدالة
النتيجة · 5 صفوف
namelowhigh
أجهزة9803200
ملحقات75210
كتب6085
قرطاسية1218
ألعاب65120

دالة بمعاملات OUT لا تحتاج RETURNS: نوع الإرجاع صف من أعمدة OUT.

لاحظ في Oracle: الاتجاه يُكتب بعد الاسم (b OUT NUMBER)، وفي PostgreSQL و MySQL قبله.

توقّع وتحقّق

معامل يدخل بقيمة ويخرج بقيمة جديدة:

عند CALL مباشرة نضع مكان معاملات OUT:

ما فائدة DEFAULT في المعامل؟

في MySQL تُستقبل مخرجات CALL في:

الخلاصة

تحدٍّ برمجي: ملخص الطلب

متوسط

اكتب إجراء order_summary يستقبل رقم طلب ويُخرج عدد بنوده وإجماليه.

المطلوب:
  • المعاملات: IN oid int و OUT items int و OUT total numeric.
  • items عدد البنود، و total مجموع qty * unit_price.
  • طلب بلا بنود أو غير موجود يُخرج 0 و 0 لا NULL.
👀 اعرض الناتج المطلوب
✓ التحقق الآلي من حلّك:
  • الكود يعمل بلا أخطاء
  • الطلب 1 ← 2 بندان و 3350
  • الطلب 8 ← 3 بنود و 210
  • طلب غير موجود ← 0 و 0
  • معامل OUT

💡 تلميح 1
ابدأ من customer_stats في الدرس.
💡 تلميح 2
استخدم SELECT count(*), coalesce(sum(…), 0) INTO items, total.

حاول بنفسك أولًا؛ للمسألة أكثر من حلّ صحيح.

solution.sql
CREATE PROCEDURE order_summary(IN oid int, OUT items int, OUT total numeric)LANGUAGE plpgsqlAS $$BEGIN  SELECT count(*), coalesce(sum(qty * unit_price), 0)  INTO items, total  FROM order_items WHERE order_id = oid;END;$$;
انتقل إلى تقييم الدرساختيار من متعدد، وصح وخطأ، وأكمل الفراغ، وتتبّع الناتج.ابدأ التقييم ←

📝 معلم؟ أرسل ملاحظة للمؤلف عن هذا الدرس