اذهب إلى المحتوى

فهم قيود SQL


محمد الخضور

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

تُمكنّك أنظمة إدارة قواعد البيانات العلاقية RDBMSs من التحكّم بالبيانات التي يُسمح بإضافتها إلى الجدول من خلال ما يُسمّى بالقيود constraints. والقيد عبارة عن قاعدة خاصة تُفرض على عمود واحد أو أكثر، أو حتى على الجدول كاملًا، وتحدد هذه القاعدة التغييرات المتاح إجراؤها على بيانات الجدول، سواء كان هذا التغيير من هو أمر إدراج بيانات جديدة INSERT، أو تحديث بيانات موجوة UPDATE، أو حذف بيانات معينة DELETE.

سنعرض في هذا المقال مفهوم القيود وكيفية استخدامها في أنظمة RDBMS بالتفصيل، كما سنستعرض القيود الخمسة المُعرفّة في معايير SQL ونشرح الوظيفة الأساسية لكل منها.

ما هي القيود؟

القيد constraint في SQL هو أي قاعدة تُطبق على عمود أو جدول بهدف تحديد طبيعة البيانات التي يمكن إدخالها فيه. فعند كل محاولة لإجراء عملية من شأنها تغيير البيانات الموجودة في جدول – من خلال أمر إدراج INSERT أو تحديث UPDATE أو حذف DELETE للبيانات مثلًا – ستتحقق نظم إدارة قواعد البيانات العلاقية فيما إذا كانت هذه البيانات تخالف أي من القيود الموجودة أم لا، وستعيد خطأ إذا كانت تخالفها بالفعل أو ستنفذها في حال كانت تحقق المعايير المطلوبة.

يعتمد مسؤولو قواعد البيانات على القيود لضمان اتباع قاعدة البيانات لمجموعة مُحددة من قواعد وتوجيهات العمل، وفي إطار قواعد البيانات، تُعرّف القاعدة بأنها أي سياسة أو إجراء تتبعه الشركة أو أي منظمة أخرى لتحدد من خلالها كيفية تخزين البيانات في قاعدة البيانات، إذ يجب أن تتوافق بياناتها مع هذه القواعد تمامًا.

على سبيل المثال، إذا كنت تعمل على تطوير قاعدة بيانات لرصد مخزون متجر لأحد العملاء وطلب منك هذا العميل التأكد من وجود رقم تعريف فريد لكل سجل (منتج)، فبإمكانك وضع القيد UNIQUE (المُعبّر عن كون كل سجل في العمود المعني فريد) على العمود المُخصص للرقم التعريفي لضمان عدم وجود أي تكرار في القيم المدخلة لأرقام المنتجات المختلفة.

تلعب القيود دورًا مهمًا في الحفاظ على دقة وصحة البيانات أو ما يعرف بسلامة البيانات data integrity. إذ يُشير مصطلح سلامة البيانات إلى مدى دقة واتساق ومنطقية البيانات المحفوظة في قاعدة البيانات وفقًا لسياق استخدامها. فغالبًا ما تكون الجداول ضمن قاعدة البيانات مرتبطة ببعضها البعض، فقد تعتمد بعض الأعمدة في جدول معين على القيم الموجودة في جدول آخر. ونظرًا لأن الأخطاء البشرية واردة الحدوث أثناء إدخال البيانات، فإن وضع القيود أمر أساسي في مثل هذه الحالات، إذ أنها تضمن عدم تأثير البيانات المُدخلة على نحوٍ خاطئ على هذه العلاقات بما قد يؤثّر سلبًا بالنتيجة على سلامة البيانات.

بفرض أنك تُصمّم قاعدة بيانات تتضمّن جدولين: الأول لإدراج الطلاب الحاليين في مدرسة ما، والثاني لإدراج أعضاء فريق كرة السلة في تلك المدرسة. يمكنك في هذه الحالة تطبيق قيد FOREIGN KEY (قيد المفتاح الخارجي) على أحد أعمدة جدول فريق كرة السلة ليشير إلى أحد أعمدة جدول الطلاب. وهذا ما سينشئ علاقة بين الجدولين، إذ يتطلب أي إدخال جديد في جدول الفريق أن يشير إلى إدخال موجود بالفعل في جدول الطلاب.

ولدى تصميم جدول في قاعدة البيانات، يمكن للمستخدمين تحديد القيود أثناء إنشاء هذا الجدول أو إضافتها لاحقًا باستخدام إحدى تعليمات ALTER TABLE، بشرط ألّا تتعارض هذه القيود المُضافة مع البيانات الموجودة أصلًا في الجدول. وعند إنشاء قيد جديد، سيولّد نظام قاعدة البيانات تلقائيًا اسمًا له، ولكن وفي العديد من تطبيقات SQL يمكنك تحديد اسم مُخصّص للقيد. إذ يُستخدم هذا الاسم للإشارة إلى القيد ضمن مجموعة التعليمات ALTER TABLE المُتعلّقة بتعديل القيد أو إزالته.

يُعرّف المعيار الرسمي للغة SQL خمس قيود فقط وهي:

  • قيد المفتاح الأساسي PRIMARY KEY
  • قيد المفتاح الخارجي FOREIGN KEY
  • قيد القيم الفريدة UNIQUE
  • قيد التحقق CHECK
  • القيد غير فارغ NOT NULL

ملاحظة: تتضمّن العديد من نظم إدارة قواعد البيانات العلاقية الكلمة المفتاحية DEFAULT لتحديد قيمة ابتدائية افتراضية غير فارغة NULL تسند لسجلات العمود في حال عدم تحديد قيمة لحظة إضافة السجل. وتصف توثيقات بعض قواعد البيانات DEFAULT على أنها قيد، نظرًا لأن طريقة استخدامها تشابه لطريقة استخدام القيود الأخرى مثل UNIQUE أو CHECK. ولكن ومن الناحية التقنية، لا تعدّ DEFAULT قيدًا حقيقيًا لأنها لا تُحدّد أو تقيّد القيم التي يمكن إدخالها في العمود.

بالعودة إلى موضوعنا، وبعد حصولك على فهمٍ عام حول كيفية استخدام القيود، لنلقِ نظرة أعمق على كل من هذه القيود الخمسة.

القيد PRIMARY KEY

يتطلب قيد المفتاح الأساسي PRIMARY KEY أن يكون كل مُدخل في العمود المعني غير فارغ وغير مكرر، سامحًا لك باستخدام هذا العمود لتعريف كل سجل في الجدول على نحوٍ فريد.

والمفتاح key عمومًا في النموذج العلاقي عبارة عن عمود أو مجموعة من الأعمدة في جدول تضمن أن كل قيمة فيها فريدة وغير فارغة. أمّا المفتاح الأساسي فهو مفتاح خاص يستخدم لتعريف وتمييز سجلات الجدول على نحوٍ فردي، ويمكن استخدام العمود أو الأعمدة التي تكوّن مفتاح أساسي لتعريف الجدول وتحديده في باقي أجزاء قاعدة البيانات.

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

يمكنك إنشاء مفتاح أساسي في SQL باستخدام القيد PRIMARY KEY، والذي يُعدّ بالأصل مزيجًا من القيدين UNIQUE و NOT NULL. وبعد تعريف مفتاح أساسي، يُنشئ نظام إدارة قاعدة البيانات تلقائيًا فهرس index مرتبط به. والفهرس هو هيكلية في قاعدة البيانات تساعد في استرجاع البيانات من جدول ما بسرعة أكبر، وما على الاستعلامات إلّا استعراض الإدخالات الموافقة للعمود المُفهرس للعثور على القيم المترابطة (التابعة لسجل واحد) بآلية مُشابهة لاستخدام الفهرس في الكتب النصيّة العادية. الأمر الذي يسمح للمفتاح الأساسي بلعب دور المُعرّف لكل سجل في الجدول.

يمكن لكل جدول أن يتضمّن مفتاح أساسي واحد فقط، والذي قد يشتمل على عدّة أعمدة كما هو الحال بالنسبة للمفاتيح النمطية regular keys، ولكن من مميزات المفاتيح الأساسية هو استعانتها بأقل عدد ممكن من السمات لتمييز كل سجل في الجدول على نحوٍ فريد. ولتبسيط هذه الفكرة، تخيل جدولًا يُخزّن معلومات الطلاب في مدرسة ما من خلال ثلاثة أعمدة كالتالي:

  • studentID: يُستخدم لتخزين رقم التعريف (مُعرّف) الخاص بكل طالب.
  • firstName: يُستخدم لتخزين الاسم الأول لكل طالب.
  • lastName: يُستخدم لتخزين اسم العائلة لكل طالب.

ولكن قد تتطابق الأسماء الأولى لبعض الطلاب في المدرسة، ما يجعل من العمود firstName خيارًا غير مناسب للاستخدام كمفتاح أساسي. وينطبق الأمر نفسه على العمود lastName. وبالتالي، قد يكون من المناسب استخدام مفتاح أساسي يتكون من الاسم الأول والأخير معًا، ولكن يبقى احتمال وجود طلاب بنفس الاسم الكامل قائمًا.

وبالتالي، يمكن الاعتماد على مفتاح أساسي يتألف من عمود رقم تعريف الطالب studentID بالإضافة إلى عمود الاسم الأول firstName أو عمود الاسم الأخير lastName. ولكن وبما أنّ رقم تعريف كل طالب هو قيمة فريدة، فإنّ إضافة أحد أعمدة الأسماء للمفتاح الأساسي لا يُمثّل أي قيمة مُضافة. ولهذا، يعدّ استخدام عمود رقم تعريف الطالب وحده الخيار الأمثل ليكون المفتاح الأساسي لهذا الجدول.

إذا كان المفتاح مكوّنًا من بيانات تطبيقية واقعية (أي بيانات تُمثّل كيانات أو أحداث أو سمات من العالم الواقعي)، فيُطلق عليه اسم مفتاح طبيعي natural key. أمّا إذا أُنشئ المفتاح داخليًا دون أن يُمثّل أي شيء خارج قاعدة البيانات، فيُعرف حينها باسم مفتاح بديل surrogate أو مفتاح مُصنّع synthetic key. تُوصي بعض أنظمة قواعد البيانات بتجنب استخدام المفاتيح الطبيعية، فحتى البيانات التي تبدو ثابتة قد تتغير بطرق غير متوقعة.

القيد FOREIGN KEY

يفرض القيد FOREIGN KEY أن تكون كل قيمة في العمود المعني موجودة بالفعل في عمود معين من جدول آخر.

بفرض لديك جدولين، ووددت ربطهما ببعضهما البعض، فإحدى الطرق التي يمكنك استخدامها لهذا الغرض هي تعريف مفتاح خارجي باستخدام القيد FOREIGN KEY. والمفتاح الخارجي هو عمود في جدول معين (ويطلق عليه الجدول "الابن") تأتي قيمه من مفتاح في جدول آخر (ويطلق عليه "الأب" أو الجدول الرئيسي). وهذا ما يُعبّر عن علاقة بين الجدولين: فالقيد FOREIGN KEY يفرض أن تكون القيم في العمود المعني موجودة بالفعل في العمود المُشار إليه من الجدول الآخر.

يُظهر المخطط التالي هذا النوع من العلاقة بين جدولين: إذ يُستخدم الأول لتسجيل معلومات حول الموظفين في شركة، ويُستخدم الثاني لتتبع مبيعات الشركة، وقد استخدمنا في هذا المثال مفتاح خارجي في جدول المبيعات SALES يشير إلى المفتاح الأساسي من جدول الموظفين EMPLOYEES:

01.png

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

فغالبًا ما يكون المفتاح الخارجي للجدول الابن هو المفتاح الأساسي للجدول الأب، ولكن الحال ليس على هذا النحو دائمًا. ففي معظم أنظمة إدارة قواعد البيانات العلاقية يمكن للمفتاح الخارجي في الجدول الابن الإشارة إلى أي عمود مُطبّق عليه أحد القيدين PRIMARY KEY أو UNIQUE في الجدول الأب.

القيد UNIQUE

يمنع القيد UNIQUE إضافة قيم مكررة إلى العمود المعني، وكما يوحي اسمه، يتطلب هذا القيد أن تكون كل قيمة تقوم بإدخالها في العمود المعني فريدةـ وأي محاولة لإضافة قيمة موجودة بالفعل فيه ستؤدي إلى ظهور خطأ.

تفيد القيود UNIQUE في فرض علاقات من نوع واحد-إلى-واحد one-to-one بين الجداول. فرغم إمكانية تكوين علاقات بين الجداول باستخدام المفتاح الخارجي كما أشرنا سابقًا، إلّا أنّ هناك عدّة أنواع من العلاقات التي قد تظهر بين الجداول:

  • واحد-إلى-واحد: نقول بأنّ علاقة من نوع واحد-إلى-واحد تربط بين جدولين إذا كان كل سجل في الجدول الأب مرتبط بسجل واحد فقط في الجدول الابن.
  • واحد-إلى-عديد: في علاقة واحد-إلى-عديد، يمكن أن يرتبط كل سجل في الجدول الأب مع عدة سجلات في الجدول الابن، لكن كل سجل في الجدول الابن يمكن أن يرتبط بسجل واحد فقط من الجدول الأب.
  • عديد-إلى-عديد: نقول بأنّ علاقة من نوع عديد-إلى-عديد تربط بين الجدولين إذا كان بإمكان السجلات في الجدول الأب أن ترتبط مع عدّة سجلات من الجدول الابن، والعكس صحيح.

بإضافة القيد UNIQUE إلى عمود قد طُبّق عليه القيد FOREIGN KEY أيضًا، يمكنك التأكد من أن كل مُدخل في الجدول الأب يظهر مرة واحدة فقط في الجدول الابن، وبذلك تكون قد أنشأت علاقة من نوع واحد-إلى-واحد بين الجدولين.

ومن الجدير بالذكر أنّه يمكن تعريف القيود UNIQUE على مستوى الجدول أو على مستوى العمود. فعند تعريف القيد UNIQUE على مستوى الجدول، يمكن أن يشمل حينها أكثر من عمود. وفي مثل هذه الحالات، يمكن لكل عمود مُدرج ضمن القيد أن يحتوي على قيم مكررة، ولكن يجب أن تكون لكل سجل مجموعة فريدة من القيم في الأعمدة الخاضعة للقيد.

القيد CHECK

يُعرّف القيد CHECK قاعدة يجب أن تُطبق على عمود معين على هيئة عبارة شرطية predicate ويجب أن تُحقق جميع القيم المُدخلة في ذلك العمود الشرط المسند لهذا العمود. حيث تُكتب شروط القيد CHECK بشكل تعبير شرطي يأخذ القيمة TRUE (صحيح/مُحقق) أو FALSE (خاطئ/غير مُحقق)، أو حتى UNKNOWN (غير معروف وهو ما يحدث في حالة وجود قيم فارغة NULL في العمود). فإذا حاولت إدخال قيمة في عمود خاضع للقيد CHECK وتسببت هذه القيمة في تقييم الشرط إلى TRUE أو UNKNOWN فستنجح العملية وتخزن القيمة في العمود، وإذا تم تقييم التعبير إلى FALSE ستفشل ولن يسمح لك بإدخالها.

وتعتمد شروط القيد CHECK في كثير من الأحيان على عامل مقارنة رياضي (من قبيل <، >، <=، أو >=) لتحديد نطاق البيانات المسموح بإدخالها في العمود المُحدّد. فعلى سبيل المثال، من الاستخدامات الشائعة للقيود CHECK هي منع استقبال قيم سالبة في بعض الأعمدة وذلك في الحالات التي لا تكون فيها القيم السالبة مقبولة، كما سنوضح في المثال التالي.

سنكتب تعليمة CREATE TABLE لإنشاء جدول يخزن بيانات المنتجات وسنطلق عليه اسم productInfo، يحتوي هذا الجدول على أعمدة لتخزين اسم كل منتج ورقم التعريف الخاص به وسعره. ونظرًا لأن سعر المنتج لا يمكن أن يكون سالبًا من الناحية المنطقية، فنكتب قيد CHECK على عمود السعر price لضمان احتوائه على قيم موجبة فقط بالشكل التالي:

mysql> CREATE TABLE productInfo (
mysql> productID int,
mysql> name varchar(30),
mysql> price decimal(4,2)
mysql> CHECK (price > 0)
mysql> );

لا يُشترط استخدام عامل مقارنة رياضي في كل شرط من الشروط المنطقية الإسنادية الخاصة بالقيد CHECK. إذ يُمكنك استخدام أي معامل من معاملات SQL التي يمكن تقييمها في عبارة الشرط المنطقي إلى TRUE أو FALSE أو UNKNOWN، مثل LIKE و BETWEEN و IS NOT NULL وغيرها. وتسمح بعض تقديمات SQL -ولكن ليس كلها- بإضافة استعلام فرعي داخل العبارة الشرطية. في حين لا تسمح معظم التقديمات بالإشارة إلى جدول آخر داخل هذه العبارة الشرطية.

القيد NOT NULL

يحظرك القيد NOT NULL من إضافة أي قيم فارغة NULL إلى العمود المعني، فإذا أضفت سجل من البيانات ولم تُحدد فيه قيمة لعمود معين، فسوف يُمثّل نظام قواعد البيانات في معظم تقديمات SQL البيانات المفقودة افتراضيًا على أنها قيمة فارغة NULL. وفي لغة SQL تعد كلمة NULL مصطلحًا خاصًّا يُستخدم لتمثيل قيمة مجهولة أو مفقودة أو غير مُحددة. ولكن NULL ليست قيمة بحد ذاتها، بل هي حالة تُعبّر عن قيمة مجهولة أو غير متوفرة.

ولتوضيح هذا الفارق، تخيل جدولًا يُستخدم لتتبع العملاء في شركة لاستقطاب المواهب ويحتوي هذا الجدول على أعمدة لأسماء العملاء الأولى والأخيرة. فإذا كان العميل معروفًا باسمٍ واحدٍ فقط، فسيُدخل مدير قاعدة البيانات هذا الاسم في عمود الاسم الأول فقط، مما يتسبب في إدخال قيمة فارغة NULL في عمود الاسم الأخير.

في مثل هذه الحالة لا تعدّ قاعدة البيانات أن الاسم الأخير للعميل هو حرفيًا "فارغ". بل يعني ذلك فقط أن القيمة الموجودة في عمود الاسم الأخير لذلك السجل مجهولة أو غير متوفرة.

وبالتالي، وكما يوحي اسمه، يمنعك القيد NOT NULL من إدخال قيم فارغة NULL أو تجاهل إدخال قيمة في العمود المعني. وبالتالي ستكون مجبورًا على تحديد قيمة لأي عمود طُبِّق عليه قيد NOT NULL عند إضافة سجل جديد، وإلا ستفشل عملية الإدراج.

الخلاصة

تعرفنا في مقال اليوم على مفهوم القيود التي تعد أحد المفاهيم الأساسية لأي شخص يرغب في تصميم قاعدة بيانات بمستوى عالٍ من نزاهة وأمان البيانات وسلامتها. إذ يمكنك التأكد من الحفاظ على العلاقات بين الجداول على النحو الصحيح من خلال تحديد البيانات التي يُسمح بإدخالها ضمن عمود معين، ما يضمن توافق قاعدة البيانات مع القواعد المطلوبة التي تحدد الغرض من إنشائها.

للمزيد حول كيفية إنشاء وإدارة القيود في SQL، يمكنك مراجعة مقالنا كيفية استخدام القيود في SQL. وللمزيد حول SQL عمومًا، نشجعك على متابعة سلسلة تعلم SQL في أكاديمية حسوب.

ترجمة -وبتصرف- للمقال Understanding SQL Constraints لصاحبه Mark Drake.

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...