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

القيود: NOT NULL و UNIQUE و CHECK و DEFAULT

قواعد تحرسها قاعدة البيانات بنفسها، فلا تدخلها بيانات خاطئة من أي باب. ⏱ نحو 35 دقيقة.

بعد هذا الدرس ستستطيع أن:
  • تشرح دور القيود في حماية صحة البيانات.
  • تستخدم NOT NULL و UNIQUE و CHECK و DEFAULT.
  • تكتب قيودًا على مستوى الجدول وتسمّيها.
  • تفسّر رسائل مخالفة القيود.

١القيد: قاعدة لا تُخالف

التطبيق قد يخطئ، والمستخدم قد يدخل أي شيء. القيد Constraint قاعدة تفرضها قاعدة البيانات نفسها على كل إدخال وتعديل، من أي تطبيق جاء. هو آخر خط دفاع عن صحة البيانات.

القيديمنعمثال
NOT NULLالقيمة الفارغةاسم المنتج إلزامي
UNIQUEالتكرارلا يتكرر البريد الإلكتروني
CHECK (شرط)القيم المخالفة للشرطالسعر أكبر من صفر
DEFAULT قيمة(ليس منعًا) قيمة تلقائية إن لم تُرسلالحالة الافتراضية new
PRIMARY KEYالتكرار والفراغ معًاالمعرّف
REFERENCESالإشارة إلى صف غير موجودالدرس القادم

٢القيود في العمل

قاعدة المتجر مبنية بقيود. جرّب أن تخالفها:

✗ خطأ
query.sql
INSERT INTO products (name, category_id, price, stock)VALUES ('قلم', 4, -5, 10);
✗ خطأ (السطر 1): الصف الجديد في products يخالف قيد CHECK: products_price_check
✓ صواب
query.sql
INSERT INTO products (name, category_id, price, stock)VALUES ('قلم', 4, 5, 10);SELECT name, price, stock FROM products WHERE name = 'قلم';
✓ أُضيف صف واحد
النتيجة · صف واحد
namepricestock
قلم510

رسالة الخطأ تذكر اسم القيد products_price_check: PostgreSQL سمّاه تلقائيًّا من اسم الجدول والعمود.

query.sql
INSERT INTO customers (name, city, email, joined)VALUES ('سارة الثانية', 'جدة', 'sara@mail.sa', current_date);
✗ خطأ (السطر 1): قيمة مكررة: تخالف قيد التفرّد customers_email_key (PRIMARY KEY أو UNIQUE)

البريد مكرر: قيد UNIQUE رفض الإدخال كاملًا.

٣قيود الجدول وتسميتها

بعض القيود تشمل أكثر من عمود، فتُكتب في آخر الجدول. وتسمية القيد بنفسك تجعل رسالة الخطأ مفهومة:

query.sql
CREATE TABLE promotions (  id         int GENERATED ALWAYS AS IDENTITY PRIMARY KEY,  product_id int NOT NULL,  starts_on  date NOT NULL,  ends_on    date NOT NULL,  percent    int NOT NULL DEFAULT 10,  CONSTRAINT promo_dates_ok    CHECK (ends_on > starts_on),  CONSTRAINT promo_percent_ok  CHECK (percent BETWEEN 1 AND 70),  CONSTRAINT promo_one_per_day UNIQUE (product_id, starts_on)); INSERT INTO promotions (product_id, starts_on, ends_on) VALUES (1, '2025-11-01', '2025-10-01');
✓ أُنشئ الجدول
✗ خطأ (السطر 12): الصف الجديد في promotions يخالف قيد CHECK: promo_dates_ok

اسم القيد في الرسالة promo_dates_ok يخبرك فورًا ما الخطأ: نهاية العرض قبل بدايته.

توقّع وتحقّق

أي قيد يمنع التكرار ويقبل NULL؟

ما الذي يفعله DEFAULT؟

قيد يقارن عمودين (النهاية بعد البداية) يُكتب:

لماذا نسمّي القيود بأنفسنا؟

الخلاصة

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

متوسط

أنشئ جدول staff لموظفي المتجر بالقيود المطلوبة.

المطلوب:
  • id مفتاح أساسي مولَّد، وname إلزامي.
  • national_id نص من 10 أرقام بالضبط، فريد (CHECK بـ ~ '^[0-9]{10}$').
  • salary numeric أكبر من 3000 وأقل من 50000.
  • role إحدى القيم cashier أو manager أو storekeeper، وافتراضيًّا cashier.
👀 اعرض الناتج المطلوب
✓ التحقق الآلي من حلّك:
  • الكود يعمل بلا أخطاء
  • موظف صحيح يُقبل، والدور افتراضيًّا cashier
  • الدور الافتراضي cashier
  • الاسم إلزامي
  • رقم الهوية 9 أرقام يُرفض
  • رقم الهوية لا يتكرر
  • راتب 2000 يُرفض
  • دور غير معروف يُرفض

💡 تلميح 1
قيد على عمود: CHECK (role IN ('cashier', 'manager', 'storekeeper')).
💡 تلميح 2
التعبير المنتظم: national_id ~ '^[0-9]{10}$' يعني عشرة أرقام بالضبط.

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

solution.sql
CREATE TABLE staff (  id          int GENERATED ALWAYS AS IDENTITY PRIMARY KEY,  name        text NOT NULL,  national_id text NOT NULL UNIQUE CHECK (national_id ~ '^[0-9]{10}$'),  salary      numeric(10,2) CHECK (salary > 3000 AND salary < 50000),  role        text NOT NULL DEFAULT 'cashier' CHECK (role IN ('cashier', 'manager', 'storekeeper')));
انتقل إلى تقييم الدرساختيار من متعدد، وصح وخطأ، وأكمل الفراغ، وتتبّع الناتج.ابدأ التقييم ←

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