18 Jun 2005
من المعروف بأن طريقة تخزين البيانات في قواعد البيانات العلائقية هي أن تكون البيانات مخزنة في صورة جداول مكونة من عدة سجلات (صفوف الجداول) كل سجل منها يحتوي على عدة حقول (أعمدة الجداول)، مثال على ذلك الجدول التالي:
الاسم | رقم الهاتف |
---|---|
مدحت | 223341 |
غلام | 244211 |
جون | 299113 |
ففي المثال السابق هنالك ثلاثة سجلات في الجدول كل منها مكون من معلومة مخزنة في أحد الحقلين الذين يعرّفان الجدول وهما الاسم ورقم الهاتف.
والطريقة المثالية لاستخدام قواعد البيانات العلائقية تقضي بعدة أمور من بينها:
وستعرف حالا لماذا ذكرت هذه الضوابط بالذات وعلاقتها بموضوعنا.
الجدول في المثال السابق يحقق كافة الضوابط التي ذكرناها، فهو مستطيل الشكل، والطريقة الطبيعية لاضافة المعلومات إليه هي باضافة سجلات جديدة يتكون كل منها من اسم للشخص الجديد ورقم هاتفه، أي معلومة واحدة لكل حقل، كما أن تصميم الجدول لا يتطلب تكرار أية معلومات فيه.
لكن المشكلة التي سنحاول حلها الآن هي كيف يمكن تعديل الجدول لكي يسمح لنا بتخزين أكثر من رقم هاتف للشخص الواحد؟ لنفرض مثلا بأن لمدحت ثلاثة أرقام هواتف مختلفة، فكيف يمكن إضافة ثلاثة أرقام إلى الجدول؟ ستناول لحل هذه المشكلة ثلاثة حلول خاطئة ونبين جانب الخطأ في كل منها ونتحدث بعد ذلك عن الحل الصحيح.
الحل الأول: نضع أكثر من رقم في حقل الهاتف ونفصل بينها بعلامة ما، فيصبح الجدول كالتالي:
الاسم | رقم الهاتف |
---|---|
مدحت | 223341،282212،299432 |
غلام | 244211 |
جون | 299113 |
فبهذه الطريقة وضنا ثلاثة أرقام بدلا من رقم واحد في حقل رقم الهاتف للسجل المتعلق بمدحت، وفصلنا بين الأرقام بعلامة الفاصلة.
لكننا نكون هنا قد أخللنا بأكثر من واحدة من ضوابط قواعد البيانات العلائقية، فقمنا أولا باضافة أكثر من قطعة بيانات في حقل واحد، وأصبح جدولنا غير مستطيل الشكل، لأن سجل مدحت أعرض بكثير من السجلين الآخرين، وإضافة بيانات جديدة إلى الجدول أصبحت تتم الآن بتعديل حقل رقم الهاتف بدلا من اضافة سجلات جديدة.
الحل الثاني: نضيف أكثر من سجل للشخص نفسه، بحيث يمكن أن يحتوي كل سجل على رقم هاتف مختلف، فيصبح جدولنا بذلك كالتالي:
الاسم | رقم الهاتف |
---|---|
مدحت | 282212 |
مدحت | 223341 |
مدحت | 299432 |
غلام | 244211 |
جون | 299113 |
في الجدول السابقة قمنا بمخالفة قاعدة أخرى وهي أنه أصبح لدينا الآن معلومة مكررة، وهي اسم مدحت، كما أنه بالنسبة لقاعدة البيانات في هذه الحالة، لا توجد أية علاقة بين مدحت الأول والثاني والثالث، ولن تعرف أبدا بأنه الشخص نفسه، والمشكلة في ذلك هي أنك إذا أردت مثلا أن تغير اسم مدحت وتضع اسمه الكامل مدحت الباشا، فانك يجب أن تتذكر القيام بذلك ثلاثة مرات، مرة لكل واحدة من الأرقام الثلاثة، كما أنك إذا انهيت علاقتك بمدحت وأردت حذف أرقامه، فان عليك حذف كل رقم على حدى.
الحل الثالث: نضع كل رقم من أرقام مدحت في خانة منفصلة.
الاسم | رقم الهاتف1 | رقم الهاتف2 | رقم الهاتف3 |
---|---|---|---|
مدحت | 223341 | 282212 | 299432 |
غلام | 244211 | ||
جون | 299113 |
لكننا خالفنا القواعد هنا أيضا، فجدولنا ليس مستطيل الشكل الآن، كما أن إضافة بيانات إلى الجدول تتم الآن بتعديل السجلات، ومشكلة أخرى تظهر هنا وهي ماذا لو أردنا أن نضع لمدحت رقم رابع؟ هل سنقوم بتعديل بنية الجدول بأكمله ونضيف خانة رابعة لرقم الهاتف الرابع فقط لإضافة معلومة واحدة إلى احدى السجلات؟
سؤالان الآن إلى الذهن:
وسنبدأ بالإجابة عن السؤال الثاني أولا: لماذا يجب الالتزام بضوابط قواعد البيانات العلائقية؟
والإجابة هي أن أنظمة وبرامج قواعد البيانات العلائقية صممت بالأساس لتستخدم وفقا لهذه الضوابط، فقد صممت مثلا لتكون عملية إضافة سجلات جديدة إلى جدول ما أسرع بكثير من عملية تعديل بنية الجدول وإضافة حقل جديد إليه.
كما أنها صممت لتجعل البيانات تحتل أصغر مساحة ممكنة مع تحقيق أعلى سرعة ممكنة عندما تكون الجداول مستطيلة، لكن عندما تصبح الجداول غير مستطيلة ويكون هنالك تباين كبير في أحجام سجلاتها فإن البيانات ستحتل الكثير من المساحة الزائدة دون أن يكون هنالك داع لذلك.
أضف إلى ذلك أن لغة SQL المستخدمة للتعامل مع قواعد البيانات صممت لكي تتعامل مع البيانات على هذا الأساس، فالأمر الذي يضيف سجلا جديدا إلى قواعد البيانات اسمه ADD بينما الأمر الذي يضيف حقلا جديدا إلى الجدول اسمه ALTER TABLE.
أما السؤال الأول: ما هو الحل الصحيح الذي يرضي ضوابط قواعد البيانات؟ فالإجابة عليه هي الهدف الأساسي من هذه المقالة، وبالإضافة إلى الإجابة عن هذا السؤال، فإن فهمك لهذه المقالة سيفتح لك آفاقا جديدة في التعامل مع قواعد البيانات العلائقية، وستعرف الإجابة عن سؤال آخر قد يكون قد تبادر إلى ذهنك مرارا وهو: لماذا سمي هذا النوع من قواعد البيانات بقواعد البيانات العلائقية؟
علاقة عدة بواحد
أول نوع من العلاقات التي سننظر إليها في مرورنا على كيفية تنظيم أنواع مختلفة من البيانات في قواعد البيانات العلائقية هي علاقة تسمى عدة بواحد (many to one).
مثال على هذا النوع من العلاقات هو العلاقة التي كنا نناقش كيفية تنظيمها في قاعدة البيانات سابقا، وهي اسم لشخص واحدة له عدة أرقام هاتف، فهنالك عدة أرقام هاتفية مرتبطة باسم واحد ولذا سميت عدة بواحد.
فها قد وصلنا أخيرا إلى الحل لمشكلتنا السابقة، وهو يكون باستخدام جدولين منفصلين، الأول للأسماء والثاني لأرقام الهواتف، كالتالي:
معرف الشخص | الاسم |
---|---|
1 | مدحت |
2 | غلام |
3 | جون |
معرف الشخص | رقم الهاتف |
---|---|
1 | 282212 |
1 | 223341 |
1 | 299432 |
2 | 244211 |
3 | 299113 |
هنالك عدة أمور حدثت، وسنناقش كل جزء منها بالتفصيل حتى تصل الفكرة، ولنبدأ بتسمية الجدول الأول جدول الأشخاص والجدول الثاني جدول أرقام الهواتف.
في الجدول الأول، جدول الأشخاص، أضفنا حقلا جديدا هو حقل معرف الشخص، معرف الشخص في هذا الجدول هو عبارة عن رقم فريد لكل سجل يمكننا استخدامه للإشارة إلى سجل من هذه السجلات، فإذا قلت لك ما هو اسم الشخص الذي معرفه 1 تقول لي مباشرة مدحت، وإذا سألتك عن اسم الشخص الذي معرفه 3 تقول لي جون، ولا يمكن أن يكون هنالك أكثر من سجل له نفس المعرف، وهذا الرقم يسمى في اصطلاح قواعد البيانات العلائقية المفتاح الأولي للجدول (primary key).
وفي الجدول نجد بأن هنالك حقلا يحمل نفس الاسم أيضا وهو معرف الشخص، وهذا الحقل يحمل معرف الشخص الذي يشير إليه الرقم، والهدف منه ببساطة هو أن نعرف لمن من الأشخاص يعود له الرقم المخزن في كل سجل، ففي السجل الأول من سجلات جدول أرقام الهواتف كان معرف الشخص هو 1، أي أنه يعود إلى مدحت، وكذلك الأمر بالنسبة للسجل الثاني والثالث، فالأرقام الثلاثة الأول كلها تعود لمدحت إذا، أما السجل الرابع فهو يحتوي على الرقم 2 في حقل معرف الشخص، أي أنه يعود للشخص الذي معرفه 2، وبالعودة إلى جدول الأشخاص نعرف بأنه غلام، وهكذا الأمر بالنسبة للحقل الخامس الذي يحمل رقم هاتف جون.
ورقم الشخص في الجدول الثاني يسمى في اصطلاح قواعد البيانات العلائقية بالمفتاح الأجنبي (foreign key)، وقد سمي بذلك لأن قيمته تشير إلى حقل أجنبي على الجدول، أي حقل من حقول جدول آخر.
وبهذه الطريقة أصبحت كل الجداول مستطيلة، كما أنه أصبح بامكاننا إضافة أي عدد نريده من الأرقام لأي شخص ببساطة عن طريق إضافة سجل جديد إلى جدول أرقام الهواتف.
خلاصة ما سبق هي أن علاقة عدة بواحد تتم عن طريق ربط عدة سجلات في جدول ما بسجل واحد في جدول آخر عن طريق حقل في السجلات العدة يذكر المفتاح الأولي للعنصر الواحد.
علاقة عدة بعدة
الآن وبعد أن حللنا المشكلة السابقة، يمكننا الانطلاق قليلا بخيالنا لنحاول حل مشكلة أخرى مشابهة.
لنفرض بأنك تريد عمل قاعدة بيانات عن الكتب التي في مكتبتك، فقمت بعمل الجدول التالي:
الكتاب | المؤلف |
---|---|
المفاوضات السرية بين العرب واسرائيل | محمد حسنين هيكل |
الترويج السياحي عبر الإنترنت | طارق العيثاوي |
عام من الأزمات! 2000-2001 | محمد حسنين هيكل |
التجارة الالكترونية مبادئها ومقوماتها | يعقوب يوسف النجيدي، فيصل محمد النعيم |
لاحظ بأننا أخللنا باثنين من ضوابط قواعد البيانات، فقد قمنا بتكرار اسم محمد حسنين هيكل، كما أننا قمنا بوضع أكثر من معلومة في حقل المؤلف للسجل الأخير.
ولا يمكن حل هاتان المشكلتان بنفس الطريقة السابقة، والسبب في ذلك هو أنه في العلاقة السابقة (عدة بواحد) كان هنالك عدة أرقام للشخص واحد، لكننا لم نكن بحاجة لطريقة لتخزين عدة أشخاص لنفس الرقم، أما في هذا المثال الأخير، فإن الكتاب الواحد يمكن أن يكون له أكثر من مؤلف، والمؤلف الواحد يمكن أن يكون له أكثر من كتاب، ولهذا السبب فإن هذه العلاقة تسمى علاقة عدة بعدة (many to many).
فلو قمنا بتقسيم الجدول إلى جدولين، واحد للكتب وواحد للمؤلفين، سنجد بأننا نحتاج لطريقة للربط بين عدة كتب لمؤلف واحد وعدة مؤلفين لكتاب واحد، وبالتالي فإن أي سجل من أي من الجدولين يمكن أن يرتبط بأكثر من سجل في الجدول الآخر.
ولحل هذه المشكلة نقوم أولا بتقسيم الجدول إلى جدولين منفصلين يحتوي كل منهما على مفتاح أساسي دون أن يحتوي أي منهما على مفتاح أجنبي، كالتالي:
معرف الكتاب | الكتاب |
---|---|
1 | المفاوضات السرية بين العرب واسرائيل |
2 | الترويج السياحي عبر الإنترنت |
3 | عام من الأزمات! 2000-2001 |
4 | التجارة الالكترونية مبادئها ومقوماتها |
معرف المؤلف | المؤلف |
---|---|
1 | محمد حسنين هيكل |
2 | طارق العيثاوي |
3 | يعقوب يوسف النجيدي |
4 | فيصل محمد النعيم |
وبعد القيام بذلك، نقوم بعمل جدول ثالث تكون وظيفته الربط بين الجدولين السابقين:
معرف الكتاب | معرف المؤلف |
---|---|
1 | 1 |
2 | 2 |
3 | 1 |
4 | 3 |
4 | 4 |
وكل من الحقلين معرف الكتاب ومعرف المؤلف في جدول الربط هو عبارة عن مفتاح أجنبي، وبهذه الطريقة عندما أريد إضافة كتاب جديد إلى قاعدة البيانات فإنني أضيف اسم الكتاب إلى جدول الكتاب وبعد ذلك أضيف اسم المؤلف أو المؤلفين إلى جدول المؤلف إن لم تكن أسمائهم قد أضيفت من قبل لكتب أخرى لهم، ثم أضيف سجلا يربط بين الكتاب والمؤلف أو المؤلفين في جدول الربط.
وبهذه الطريقة يمكنك بسهولة البحث عن أسماء مؤلفي كتاب معين، ويمكنك أيضا بسهولة البحث عن أسماء الكتب التي لمؤلف معين.
علاقة الابن بالأب (أشجار البيانات)
حتى تكتمل الصورة لديك حول الاستخدامات المختلفة للعلاقات في قواعد البيانات العلائقية، سأمر أخيرا على علاقة الأبن بالأب (sibling to parent) لتكوين ما يسمى بأشجار البيانات (data trees)، وكعادتنا سنأخذ مثالا على ذلك لنوضح طريقة تمثيل هذا النوع من البيانات في قواعد البيانات العلائقية.
لنفرض أنك تريد عمل دليل بأنواع الكتب التي في مكتبتك، فقررت بأنك ستقسم الكتب أولا إلى عدة أقسام رئيسية يتفرع من كل قسم منها مجموعة من الأقسام الفرعية، فقمت بعمل جدول للأقسام الرئيسية وآخر للأقسام الفرعية وربطت الأقسام الفرعية بالرئيسية بعلاقة عدة بواحد.
لنفرض بأن الكتب ازدادت في مكتبك وازداد تنوعها، وظهرت لديك الحاجة لتقسيم الأقسام الفرعية مجددا إلى أقسام أدق منها، قد يكون الحل هو بانشاء جدول جديد للأقسام المتفرعة عن الفرعية، لكن ماذا إذا أردت أن تتفرع أكثر فهل ستستمر بإضافة الجداول؟
كما أن هذه الطريقة تحتوي على مشكلة، وهي أن الكتب قد تكون أحيانا تحت الأقسام الرئيسية مباشرة، وأحيانا تحت الأقسام الفرعية وأحيانا تحت المتفرعة عن الفرعية، وهذا الأمر يعقد الأمور، لأنك في الحالة العادية ستربط الكتب بالأقسام بعلاقة عدة إلى واحد، ولتحقيق ذلك فإنك تحتاج إلى حقل في سجل الكتاب يكون عبارة عن المفتاح الأجنبي المرتبط بالمفتاح الرئيسي للقسم الذي يوجد تحته الكتاب، لكن المشكلة هي هل ستربط هذا المفتاح الأجنبي بالمفتاح الرئيسي لجدول الأقسام الرئيسية أم الفرعية أم المتفرعة عن الفرعية؟
والسبب في هذه المشكلة هي أنك قمت بعمل أكثر من جدول لتخزين بيانات نفس النوع من العناصر، وهو الأقسام.
الحل لذلك يكون في دمج كل هذه الجداول في جدول واحد، ولكن كيف ستفرق بعد ذلك بين الأقسام الرئيسية والفرعية والمتفرعة عن الفرعية والمتفرعة عنها وهلم جرا؟
طريقة تحقيق ذلك تكون باضافة حقل في سجل الأقسام يحدد القسم الأب لهذا القسم، وهذا الحقل ينشئ ما يسمى بعلاقة الابن بالأب في الجدول، أما الأقسام الرئيسية التي لا تتفرع عن أي قسم آخر فتوضع بها عادة القيمة 0 (صفر) في حقل الأب.
وعلى فرض أن لديك قسمان رئيسيان هما الكمبيوتر والطب، وتحت الكمبيوتر كان هنالك البرمجة وقواعد البيانات، وتحت البرمجة كان لديك لغة C ولغة PHP فإن جدولك سيكون كالتالي:
معرف القسم | الأب | اسم القسم |
---|---|---|
1 | 0 | الكمبيوتر |
2 | 0 | الطب |
3 | 1 | البرمجة |
4 | 1 | قواعد البيانات |
5 | 3 | لغة C |
6 | 3 | لغة PHP |
كما تلاحظ فإن حقل الأب في قسمي الكمبيوتر والطب يحتوي على القيمة 0 (صفر)، أي أنهما قسمان رئيسيان لا يتفرعان عن قسم أب، أما في سجلي البرمجة وقواعد البيانات فقد كان حقل الأب يحتوي على القيمة 1، أي أنهما يتفرعان عن السجل الذي مفتاحة الأولي هو 1 وهو قسم الكمبيوتر، وأما السجلين الأخيرين لغة C ولغة PHP فقد احتوى حقل الأب لهما على القيمة 3، وهي المفتاح الأولي لسجل البرمجة الذي يتفرعان عنه.
وهكذا يمكنك بسهولة إضافة قسم جديد تحت أي قسم آخر، ولأي عمق تريده، دون الحاجة لتغيير شيء في جداول قاعدة البيانات.