الكتلة الإجرائية: المتغيرات والشروط والحلقات
المتغيرات والشروط والحلقات: أدوات التفكير خطوة بخطوة داخل قاعدة البيانات. ⏱ نحو 40 دقيقة.
- تكتب كتلة بأقسامها
DECLAREوBEGINوEND. - تعرّف متغيرات بأنواعها وتسند لها بـ := وتستخدم %
TYPE. - تكتب الشروط
IF/ELSIF/ELSEوCASE. - تكتب الحلقات
FORوWHILEوLOOPمعEXIT.
١بنية الكتلة
كل برنامج في PL/pgSQL (وفي PL/SQL) كتلة من ثلاثة أقسام:
| القسم | وظيفته | إلزامي؟ |
|---|---|---|
DECLARE | تعريف المتغيرات والثوابت | لا (إن لم توجد متغيرات) |
BEGIN … END | الأوامر التي تُنفّذ بالترتيب | نعم |
EXCEPTION | معالجة الأخطاء (الدرس 18) | لا |
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 $$;
الإسناد بـ := (لا = وحدها). والمتغير الذي لا تعطيه قيمة يبدأ NULL. التعليق بعد -- يتجاهله المحرك.
٢نوع المتغير من عمود الجدول: %TYPE
إن كان المتغير سيحمل قيمة من عمود، فاجعل نوعه نوع العمود نفسه بـ جدول.عمود%TYPE. لو تغيّر نوع العمود لاحقًا، تتبعه الكتلة تلقائيًّا:
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 $$;
SELECT … INTO يملأ أكثر من متغير بالترتيب. و%TYPE موجودة بالصياغة نفسها في Oracle.
٣الشروط: IF و CASE
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 $$;
الكلمة ELSIF (بلا E بعد S)، وكل IF تُغلق بـ END IF;. جرّب المنتج 6 (مخزونه 0) والمنتج 1.
وCASE تختار قيمة حسب الحالة، داخل الكتلة أو داخل SELECT نفسه:
SELECT name, stock, CASE WHEN stock = 0 THEN 'نفد' WHEN stock < 5 THEN 'منخفض' ELSE 'متوفر' END AS الحالةFROM products WHERE category_id = 1;
| name | stock | الحالة |
|---|---|---|
| حاسب محمول | 7 | متوفر |
| جهاز لوحي | 12 | متوفر |
| شاشة 27 بوصة | 4 | منخفض |
٤الحلقات
| الحلقة | متى؟ |
|---|---|
FOR i IN 1..5 LOOP … END LOOP; | عدد مرات معروف |
WHILE شرط LOOP … END LOOP; | تتكرر ما دام الشرط صحيحًا |
LOOP … EXIT WHEN شرط; … END LOOP; | حلقة عامة تخرج منها بشرط |
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 $$;
توقّع وتحقّق
ما علامة الإسناد في PL/pgSQL؟
ما الذي يجعل نوع المتغير مطابقًا لعمود الجدول؟
كيف يُكتب «وإلا إذا» في PL/pgSQL؟
كم مرة تُنفّذ FOR i IN 2..5؟
الخلاصة
- الكتلة:
DECLAREللمتغيرات، وBEGIN…ENDللأوامر، وEXCEPTIONللأخطاء. - الإسناد
:=، والمتغير بلا قيمة =NULL. جدول.عمود%TYPEيجعل نوع المتغير مطابقًا للعمود.IF…ELSIF…ELSE…END IF، وCASE WHENداخل الكتلة أوSELECT.FOR i IN a..b، وWHILE، وLOOPمعEXIT WHEN؛ واحذر الحلقة التي لا تنتهي.
تحدٍّ برمجي: تقرير المخزون
متوسطاكتب كتلة تمر على المنتجات من 1 إلى 6 وتطبع حالة مخزون كل منها.
- حلقة
FOR i IN 1..6. - في كل دورة: اقرأ اسم المنتج ومخزونه بـ
SELECT … INTOبالمعرّف i. - اطبع:
الاسم: نفدإن كان المخزون 0، والاسم: منخفضإن كان أقل من 5، وإلاالاسم: متوفر.
👀 اعرض الناتج المطلوب
- الكود يعمل بلا أخطاء
- حاسب محمول: متوفر
- شاشة 27 بوصة: منخفض
- سماعة رأس: نفد
- فأرة لاسلكية: متوفر
- حلقة FOR
- شرط IF … ELSIF
💡 تلميح 1
WHERE id = i.💡 تلميح 2
RAISE NOTICE '%: نفد', v_name;حاول بنفسك أولًا؛ للمسألة أكثر من حلّ صحيح.
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 $$;