طَبِّقْهاتعلّم المبدأ، وطبّقه بيدكمقرر 122 · برمجة قواعد البيانات
الدرس 2 · الوحدة 1: مقدمة للبرمجة الإجرائية

الكتلة الإجرائية: المتغيرات والشروط والحلقات

المتغيرات والشروط والحلقات: أدوات التفكير خطوة بخطوة داخل قاعدة البيانات. ⏱ نحو 40 دقيقة.

بعد هذا الدرس ستستطيع أن:
  • تكتب كتلة بأقسامها DECLARE و BEGIN و END.
  • تعرّف متغيرات بأنواعها وتسند لها بـ := وتستخدم %TYPE.
  • تكتب الشروط IF/ELSIF/ELSE و CASE.
  • تكتب الحلقات FOR و WHILE و LOOP مع EXIT.

١بنية الكتلة

كل برنامج في PL/pgSQL (وفي PL/SQL) كتلة من ثلاثة أقسام:

القسموظيفتهإلزامي؟
DECLAREتعريف المتغيرات والثوابتلا (إن لم توجد متغيرات)
BEGIN … ENDالأوامر التي تُنفّذ بالترتيبنعم
EXCEPTIONمعالجة الأخطاء (الدرس 18)لا
query.sql
DO $$DECLARE  shop_name  text    := 'متجر الريان';   -- نص  vat        numeric := 0.15;           -- عدد عشري  opened     date    := '2025-01-01';   -- تاريخ  is_open    boolean := true;           -- منطقي  visits     int;                       -- بلا قيمة أولية = NULLBEGIN  visits := 120;  RAISE NOTICE '% مفتوح؟ % · الضريبة % · منذ % · الزيارات %', shop_name, is_open, vat, opened, visits;END $$;
NOTICE: متجر الريان مفتوح؟ t · الضريبة 0.15 · منذ 2025-01-01 · الزيارات 120
✓ نُفّذت الكتلة

الإسناد بـ := (لا = وحدها). والمتغير الذي لا تعطيه قيمة يبدأ NULL. التعليق بعد -- يتجاهله المحرك.

٢نوع المتغير من عمود الجدول: %TYPE

إن كان المتغير سيحمل قيمة من عمود، فاجعل نوعه نوع العمود نفسه بـ جدول.عمود%TYPE. لو تغيّر نوع العمود لاحقًا، تتبعه الكتلة تلقائيًّا:

query.sql
DO $$DECLARE  p_name  products.name%TYPE;  p_price products.price%TYPE;BEGIN  SELECT name, price INTO p_name, p_price FROM products WHERE id = 2;  RAISE NOTICE 'المنتج: % · السعر: % ريال', p_name, p_price;END $$;
NOTICE: المنتج: جهاز لوحي · السعر: 1450.00 ريال
✓ نُفّذت الكتلة

SELECT … INTO يملأ أكثر من متغير بالترتيب. و%TYPE موجودة بالصياغة نفسها في Oracle.

٣الشروط: IF و CASE

query.sql
DO $$DECLARE  qty int;BEGIN  SELECT stock INTO qty FROM products WHERE id = 3;  IF qty = 0 THEN    RAISE NOTICE 'نفد المخزون';  ELSIF qty < 5 THEN    RAISE NOTICE 'مخزون منخفض: % فقط', qty;  ELSE    RAISE NOTICE 'متوفر';  END IF;END $$;
NOTICE: مخزون منخفض: 4 فقط
✓ نُفّذت الكتلة

الكلمة ELSIF (بلا E بعد S)، وكل IF تُغلق بـ END IF;. جرّب المنتج 6 (مخزونه 0) والمنتج 1.

وCASE تختار قيمة حسب الحالة، داخل الكتلة أو داخل SELECT نفسه:

query.sql
SELECT name, stock,       CASE WHEN stock = 0 THEN 'نفد'            WHEN stock < 5 THEN 'منخفض'            ELSE 'متوفر' END AS الحالةFROM products WHERE category_id = 1;
النتيجة · 3 صفوف
namestockالحالة
حاسب محمول7متوفر
جهاز لوحي12متوفر
شاشة 27 بوصة4منخفض

٤الحلقات

الحلقةمتى؟
FOR i IN 1..5 LOOP … END LOOP;عدد مرات معروف
WHILE شرط LOOP … END LOOP;تتكرر ما دام الشرط صحيحًا
LOOP … EXIT WHEN شرط; … END LOOP;حلقة عامة تخرج منها بشرط
query.sql
DO $$DECLARE  total numeric := 0;  balance numeric := 1000;  months int := 0;BEGIN  FOR i IN 1..3 LOOP    total := total + i * 100;    RAISE NOTICE 'الدورة %: المجموع %', i, total;  END LOOP;   WHILE balance < 1500 LOOP      -- كم شهرًا حتى يصل الرصيد 1500 بربح 10%؟    balance := balance * 1.10;    months := months + 1;  END LOOP;  RAISE NOTICE 'بعد % أشهر يصبح الرصيد %', months, round(balance, 2);END $$;
NOTICE: الدورة 1: المجموع 100
NOTICE: الدورة 2: المجموع 300
NOTICE: الدورة 3: المجموع 600
NOTICE: بعد 5 أشهر يصبح الرصيد 1610.51
✓ نُفّذت الكتلة

توقّع وتحقّق

ما علامة الإسناد في PL/pgSQL؟

ما الذي يجعل نوع المتغير مطابقًا لعمود الجدول؟

كيف يُكتب «وإلا إذا» في PL/pgSQL؟

كم مرة تُنفّذ FOR i IN 2..5؟

2 و3 و4 و5.

الخلاصة

تحدٍّ برمجي: تقرير المخزون

متوسط

اكتب كتلة تمر على المنتجات من 1 إلى 6 وتطبع حالة مخزون كل منها.

المطلوب:
  • حلقة FOR i IN 1..6.
  • في كل دورة: اقرأ اسم المنتج ومخزونه بـ SELECT … INTO بالمعرّف i.
  • اطبع: الاسم: نفد إن كان المخزون 0، والاسم: منخفض إن كان أقل من 5، وإلا الاسم: متوفر.
👀 اعرض الناتج المطلوب
NOTICE: حاسب محمول: متوفر
NOTICE: جهاز لوحي: متوفر
NOTICE: شاشة 27 بوصة: منخفض
NOTICE: فأرة لاسلكية: متوفر
NOTICE: لوحة مفاتيح: متوفر
NOTICE: سماعة رأس: نفد
✓ التحقق الآلي من حلّك:
  • الكود يعمل بلا أخطاء
  • حاسب محمول: متوفر
  • شاشة 27 بوصة: منخفض
  • سماعة رأس: نفد
  • فأرة لاسلكية: متوفر
  • حلقة FOR
  • شرط IF … ELSIF

💡 تلميح 1
ضع SELECT INTO داخل الحلقة: WHERE id = i.
💡 تلميح 2
الرسالة: RAISE NOTICE '%: نفد', v_name;

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

solution.sql
DO $$DECLARE  v_name  products.name%TYPE;  v_stock products.stock%TYPE;BEGIN  FOR i IN 1..6 LOOP    SELECT name, stock INTO v_name, v_stock FROM products WHERE id = i;    IF v_stock = 0 THEN      RAISE NOTICE '%: نفد', v_name;    ELSIF v_stock < 5 THEN      RAISE NOTICE '%: منخفض', v_name;    ELSE      RAISE NOTICE '%: متوفر', v_name;    END IF;  END LOOP;END $$;
انتقل إلى تقييم الدرساختيار من متعدد، وصح وخطأ، وأكمل الفراغ، وتتبّع الناتج.ابدأ التقييم ←

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