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

المفاتيح الأجنبية وتعديل الجداول

كيف تحمي العلاقات بين الجداول، وكيف تطوّر الجداول بعد امتلائها بالبيانات؟ ⏱ نحو 40 دقيقة.

بعد هذا الدرس ستستطيع أن:
  • تشرح كيف يحمي المفتاح الأجنبي العلاقة من الإدخال والحذف الخاطئين.
  • تختار سلوك ON DELETE المناسب: RESTRICT أو CASCADE أو SET NULL.
  • تعدّل بنية جدول موجود بـ ALTER TABLE.
  • تضيف مفتاحًا أجنبيًّا إلى جدول فيه بيانات.

١المفتاح الأجنبي يحمي العلاقة

REFERENCES يربط العمود بمفتاح جدول آخر، فيمنع شيئين: إدخال قيمة غير موجودة في الجدول الأصل، وحذف صف في الأصل تعتمد عليه صفوف أخرى.

✗ خطأ
query.sql
INSERT INTO orders (customer_id, order_date) VALUES (99, current_date);
✗ خطأ (السطر 1): القيمة في orders غير موجودة في الجدول الأصل (المفتاح الأجنبي orders_customer_id_fkey)
✓ صواب
query.sql
INSERT INTO orders (customer_id, order_date) VALUES (8, current_date);SELECT id, customer_id, status FROM orders WHERE customer_id = 8;
✓ أُضيف صف واحد
النتيجة · صف واحد
idcustomer_idstatus
138new

العميل 99 غير موجود، فرُفض الطلب. والعميل 8 (ماجد) موجود.

query.sql
DELETE FROM customers WHERE id = 1;
✗ خطأ (السطر 1): لا يمكن الحذف أو التعديل في customers: صفوف في orders تعتمد عليه (orders_customer_id_fkey)

سارة لها طلبات، فلا يمكن حذفها. هذا السلوك الافتراضي: NO ACTION (ومثله RESTRICT).

٢ماذا يحدث عند حذف الأصل؟ ON DELETE

الخيارعند حذف صف الأصلمثال مناسب
RESTRICT / NO ACTIONيُرفض الحذف (الافتراضي)عميل له طلبات
CASCADEتُحذف الصفوف التابعة معهبنود الطلب تُحذف مع الطلب
SET NULLيصبح المفتاح الأجنبي NULLمنتج حُذف تصنيفه فيبقى بلا تصنيف
SET DEFAULTيأخذ القيمة الافتراضيةنقل إلى «تصنيف عام»

في قاعدة المتجر بنود الطلب معرّفة بـ ON DELETE CASCADE. احذف الطلب 1 وراقب بنوده:

query.sql
SELECT count(*) AS قبل FROM order_items WHERE order_id = 1;DELETE FROM orders WHERE id = 1;SELECT count(*) AS بعد FROM order_items WHERE order_id = 1;
النتيجة · صف واحد
قبل
2
✓ حُذف صف واحد
النتيجة · صف واحد
بعد
0

حُذف البندان مع الطلب تلقائيًّا. CASCADE قوي، فاستخدمه حيث لا معنى للتابع دون أصله فقط.

٣تعديل جدول موجود: ALTER TABLE

الجداول تتطور مع النظام. ALTER TABLE يعدّل البنية دون حذف البيانات:

query.sql
ALTER TABLE products ADD COLUMN discount numeric(5,2) NOT NULL DEFAULT 0;ALTER TABLE products ADD CONSTRAINT discount_range CHECK (discount BETWEEN 0 AND 50);ALTER TABLE products RENAME COLUMN stock TO qty_in_stock; SELECT id, name, qty_in_stock, discount FROM products WHERE id <= 3;
✓ عُدِّل
✓ عُدِّل
✓ عُدِّل
النتيجة · 3 صفوف
idnameqty_in_stockdiscount
1حاسب محمول70
2جهاز لوحي120
3شاشة 27 بوصة40

العمود الجديد أخذ القيمة الافتراضية 0 في كل الصفوف القديمة. و NOT NULL على عمود جديد يحتاج DEFAULT، وإلا رُفض لأن الصفوف القديمة ستكون فارغة.

العمليةالأمر
إضافة عمودALTER TABLE t ADD COLUMN c type;
حذف عمودALTER TABLE t DROP COLUMN c;
إعادة تسمية عمودALTER TABLE t RENAME COLUMN a TO b;
تغيير النوعALTER TABLE t ALTER COLUMN c TYPE numeric(10,2);
إضافة قيدALTER TABLE t ADD CONSTRAINT n CHECK (…);
إضافة مفتاح أجنبيALTER TABLE t ADD FOREIGN KEY (c) REFERENCES p(id);

توقّع وتحقّق

ما السلوك الافتراضي عند حذف صف أصل له صفوف تابعة؟

أنسب خيار لبنود الطلب عند حذف الطلب:

لتغيير اسم عمود نكتب:

في Oracle يُغيَّر نوع العمود بـ:

الخلاصة

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

متقدم

أضف إلى المتجر جدول الموردين، واربط المنتجات به، بحيث إذا حُذف مورد بقيت منتجاته بلا مورد.

المطلوب:
  • جدول suppliers (id int IDENTITY PK, name text NOT NULL) وأضف إليه موردًا واحدًا على الأقل.
  • عمود جديد supplier_id في products، مفتاح أجنبي إلى suppliers مع ON DELETE SET NULL.
  • اجعل مورد المنتجات من 1 إلى 3 هو المورد رقم 1.
👀 اعرض الناتج المطلوب
✓ التحقق الآلي من حلّك:
  • الكود يعمل بلا أخطاء
  • المنتجات 1–3 مرتبطة بالمورد 1
  • مورد غير موجود يُرفض
  • حذف المورد يجعل منتجاته بلا مورد
  • ON DELETE SET NULL

💡 تلميح 1
أضف العمود والمفتاح معًا: ALTER TABLE products ADD COLUMN supplier_id int REFERENCES suppliers(id) ON DELETE SET NULL;
💡 تلميح 2
ثم UPDATE products SET supplier_id = 1 WHERE id BETWEEN 1 AND 3;

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

solution.sql
CREATE TABLE suppliers (  id   int GENERATED ALWAYS AS IDENTITY PRIMARY KEY,  name text NOT NULL);INSERT INTO suppliers (name) VALUES ('مؤسسة النور'); ALTER TABLE products  ADD COLUMN supplier_id int REFERENCES suppliers(id) ON DELETE SET NULL; UPDATE products SET supplier_id = 1 WHERE id BETWEEN 1 AND 3;
انتقل إلى تقييم الدرساختيار من متعدد، وصح وخطأ، وأكمل الفراغ، وتتبّع الناتج.ابدأ التقييم ←

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