مختصر كتابي: Primary and Candidate Keys

Summary: Primary and Candidate Keys

كيف نحدد صفًا واحدًا بعينه دون أي لبس؟

لدى خدمة العملاء طلبان، وصاحب كل منهما اسمه عمر محمد، وكتب الموظف: «عدّل عنوان عمر محمد». أيهما؟ الاسم مفيد للتعارف، لكنه لا يضمن تحديد شخص واحد.

إنفوجرافيك: إنفوجرافيك يشرح المفتاح الأساسي والمرشح وكيف نحدد صفا واحدا دون لبس.
ملخص الدرس في صورة واحدة. اضغط على الصورة لتكبيرها.

المفتاح (Key) عمود واحد أو عدة أعمدة معًا نميّز بها الصف عن أي صف آخر. والمفتاح المرشح (Candidate Key) مفتاح يمكن الاعتماد عليه: قيمه موجودة دائمًا، ولا يتكرر، ولا يحوي عمودًا زائدًا. فلو أضفنا الاسم إلى رقم العميل لما تغيّر شيء، أي أن الاسم عمود زائد.

إن كان لكل حساب بريد واحد لا يتكرر ولا يكون فارغًا، فالبريد مرشح ورقم العميل الداخلي مرشح آخر. نختار أحدهما مفتاحًا أساسيًا (Primary Key)، ونحمي الآخر بمنع التكرار ومنع الفراغ. ونفضّل الرقم الداخلي لأن العميل قد يغيّر بريده، ونريد أن تبقى طلباته مرتبطة به. الرقم الذي نضيفه للتعريف هو المفتاح البديل (Surrogate Key)، والقيمة ذات المعنى في المجال، كرقم تسجيل رسمي، هي المفتاح الطبيعي (Natural Key). لا يوجد خيار أفضل دائمًا؛ نوازن بين الثبات والحجم والخصوصية وضمان التفرّد.

CREATE TEMP TABLE key_customers(
 id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
 name text NOT NULL,
 email text UNIQUE NOT NULL
);
CREATE TEMP TABLE key_orders(
 id bigint PRIMARY KEY,
 public_code text UNIQUE NOT NULL,
 customer_id bigint NOT NULL REFERENCES key_customers
);
INSERT INTO key_customers(name,email) VALUES
 ('Omar Mohamed','[email protected]'),('Omar Mohamed','[email protected]');
INSERT INTO key_orders VALUES(100,'ORD-A100',1);
UPDATE key_customers SET email='[email protected]' WHERE id=1;

شخصان بالاسم نفسه دون مشكلة، وبعد تغيير البريد يبقى الطلب 100 للعميل 1. بخاصية IDENTITY تولّد قاعدة البيانات القيمة، لكن التوليد شيء والتفرّد شيء آخر؛ فالمفتاح الأساسي هو ما يمنع التكرار والفراغ. وقد تكون في الأرقام المولّدة فجوات، فلا تحسب عدد الطلبات من آخر رقم، ولا تفترض أن الرقم الناقص يعني حذف طلب.

وليس كل جدول بحاجة إلى رقم جديد. في بنود الطلب يظهر المنتج مرة واحدة في الطلب، فنحدد البند برقم الطلب مع رقم المنتج، وهذا مفتاح مركّب (Composite Key). القيد ينظر إلى العمودين معًا: تكرار الزوج نفسه مرفوض حتى لو اختلف عدد القطع، أما منتج آخر في الطلب نفسه فمقبول.

CREATE TEMP TABLE key_items(
 order_id bigint REFERENCES key_orders,
 product_id bigint,
 quantity integer,
 PRIMARY KEY(order_id,product_id)
);
INSERT INTO key_items VALUES(100,101,2),(100,102,1);
INSERT INTO key_items VALUES(100,101,1); -- تكرار الزوج
  • إن سمح المتجر بالمنتج مرتين في الطلب بخصمين مختلفين، نعطي كل بند رقمًا خاصًا؛ فقواعد المتجر هي التي تحدد المفتاح.
  • المفتاح الأساسي لا يعد بترتيب الصفوف عند القراءة؛ اكتب ORDER BY إن احتجت ترتيبًا.
  • في Postgres لا يعني وجود المفتاح أن الصفوف محفوظة على القرص بترتيبه.
  • صعوبة تخمين رقم الطلب ليست بديلًا عن فحص الصلاحية: الهوية تحدد أي صف، والصلاحية تحدد من يراه.
  • المفتاح الكبير أو كثير التغيّر يؤثر على كل الجداول المرتبطة به.
  • كود الفاتورة الظاهر للعميل إن كان يحدد طلبًا واحدًا فيجب منع تكراره وفراغه بنفسك، فالمفتاح الداخلي لا يمنع ذلك.

الخلاصة: اسأل دائمًا: إن غيّرنا هذه القيمة، هل ما زلنا نتحدث عن الكيان نفسه أم عن كيان جديد؟ الإجابة تحدد المفتاح المناسب، وتفرّق بين اسم الصف وهويته والكود الظاهر للعميل وترتيب العرض.

هذا درس مجاني من «هندسة قواعد البيانات». اشترك للوصول إلى كل الدروس والاختبارات والشهادة.

اعرف تفاصيل الاشتراك ←