المفتاح الأساسي والمفتاح الخارجي في SQLite مع الأمثلة
⚡ ملخص ذكي
المفاتيح الأساسية والمفاتيح الخارجية في SQLite فرض سلامة البيانات من خلال تحديد كل صف بشكل فريد وربط الجداول ذات الصلة، مما يضمن وجود القيم المشار إليها دائمًا ويمنع السجلات المكررة أو الفارغة أو اليتيمة عبر قاعدة البيانات العلائقية.
تشرح الأقسام التالية SQLite القيود بالتفصيل، بدءًا من المفتاح الأساسي والمفتاح الخارجي اللذين يحددان ويربطان الجداول، وتغطية قواعد NOT NULL و DEFAULT و UNIQUE و CHECK التي تتحقق من صحة البيانات في كل عمود.
SQLite القيود
تُطبّق قيود الأعمدة قواعد على القيم المُدخلة في عمود ما للتحقق من صحة البيانات. تُعرّف هذه القيود عند إنشاء جدول، ضمن تعريف العمود. وهي تحافظ على اتساق البيانات المخزنة ودقتها برفض القيم التي تُخالف القواعد المُحددة، مثل القيم المُكررة أو الفارغة أو القيم غير الموجودة في جدول ذي صلة.
SQLite المفتاح الأساسي
يجب أن تكون جميع القيم في عمود المفتاح الأساسي فريدة وغير فارغة. يُعرّف المفتاح الأساسي كل صف في الجدول بشكل فريد.
يمكن تطبيق المفتاح الأساسي على عمود واحد فقط أو على مجموعة من الأعمدة. في الحالة الأخيرة، يجب أن تكون مجموعة قيم الأعمدة فريدة لجميع صفوف الجدول.
بناء الجملة:
توجد عدة طرق مختلفة لتعريف المفتاح الأساسي في الجدول:
في تعريف العمود نفسه:
ColumnName INTEGER NOT NULL PRIMARY KEY;
كتعريف منفصل:
PRIMARY KEY(ColumnName);
لإنشاء مجموعة من الأعمدة كمفتاح أساسي:
PRIMARY KEY(ColumnName1, ColumnName2);
SQLite قيود NOT NULL و DEFAULT و UNIQUE و CHECK
إلى جانب المفتاح الأساسي، SQLite يُوفّر هذا النظام عدة قيود على الأعمدة للتحقق من صحة القيم المُدخلة في الجدول. يتم تعريف قيود NOT NULL وDEFAULT وUNIQUE وCHECK في تعريف العمود، ويفرض كل منها قاعدة مُحددة على العمود. نوع البيانات والقيم.
ليس القيد فارغة
استخدم SQLite يمنع قيد NOT NULL عمودًا من أن يحتوي على قيمة فارغة (null):
ColumnName INTEGER NOT NULL;
القيد الافتراضي
مع SQLite في حالة استخدام قيد القيمة الافتراضية، إذا لم تقم بإدخال أي قيمة في عمود، فسيتم إدخال القيمة الافتراضية بدلاً من ذلك.
فمثلا:
ColumnName INTEGER DEFAULT 0;
إذا كتبت عبارة إدراج ولم تحدد أي قيمة لهذا العمود، فسيكون للعمود القيمة 0.
القيد الفريد
استخدم SQLite يمنع قيد UNIQUE القيم المكررة بين جميع قيم العمود.
فمثلا:
EmployeeId INTEGER NOT NULL UNIQUE;
يضمن هذا أن تكون قيمة "EmployeeId" فريدة؛ فلا يُسمح بتكرار القيم. يُرجى ملاحظة أن هذا ينطبق على قيم عمود "EmployeeId" فقط.
التحقق من القيد
استخدم SQLite يُحدد قيد التحقق شرطًا للتحقق من القيمة المُدخلة. إذا لم تتطابق القيمة مع الشرط، فلن يتم إدخالها.
Quantity INTEGER NOT NULL CHECK(Quantity > 10);
لا يمكنك إدخال قيمة أقل من 10 في عمود "الكمية".
SQLite مفتاح غريب
استخدم SQLite المفتاح الخارجي هو قيد يتحقق من وجود قيمة موجودة في جدول ما في جدول آخر له علاقة بالجدول الأول الذي تم فيه تعريف المفتاح الخارجي.
عند التعامل مع جداول متعددة، قد يرتبط جدولان ببعضهما عبر عمود مشترك. إذا أردتَ ضمان وجود القيمة المُدخلة في أحدهما في عمود الجدول الآخر، فعليك استخدام قيد مفتاح خارجي على هذا العمود المشترك.
في هذه الحالة، عندما تحاول إدخال قيمة في ذلك العمود، سيضمن المفتاح الخارجي وجود القيمة المدخلة في عمود الجدول المشار إليه.
لاحظ أن قيود المفتاح الخارجي غير مفعلة افتراضيًا في SQLiteيجب عليك تفعيلها أولاً عن طريق تشغيل الأمر التالي:
PRAGMA foreign_keys = ON;
تم تقديم قيود المفاتيح الخارجية في SQLite بدءًا من الإصدار 3.6.19.
مثال SQLite مفتاح غريب
لنفترض أن لدينا جدولين: الطلاب والأقسام.
يحتوي جدول الطلاب على قائمة بالطلاب، بينما يحتوي جدول الأقسام على قائمة بالأقسام. ينتمي كل طالب إلى قسم معين؛ أي أن لكل طالب عمودًا خاصًا بمعرف القسم.
سنرى الآن كيف يمكن أن يكون قيد المفتاح الخارجي مفيدًا لضمان وجود قيمة معرف القسم في جدول الطلاب في جدول الأقسام.
لذا، إذا قمنا بإنشاء قيد مفتاح خارجي على DepartmentId في جدول الطلاب، فيجب أن يكون كل departmentId مدرج موجودًا في جدول الأقسام.
CREATE TABLE [Departments] ( [DepartmentId] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, [DepartmentName] NVARCHAR(50) NULL ); CREATE TABLE [Students] ( [StudentId] INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, [StudentName] NVARCHAR(50) NULL, [DepartmentId] INTEGER NOT NULL, [DateOfBirth] DATE NULL, FOREIGN KEY(DepartmentId) REFERENCES Departments(DepartmentId) );
للتحقق من كيفية منع قيود المفتاح الخارجي لإدراج عنصر أو قيمة غير محددة في جدول له علاقة بجدول آخر، سنلقي نظرة على المثال التالي.
في هذا المثال، يرتبط جدول الأقسام بجدول الطلاب عبر مفتاح خارجي، لذا يجب أن تكون أي قيمة لـ departmentId مُدرجة في جدول الطلاب موجودة في جدول الأقسام. إذا حاولتَ إدراج قيمة departmentId غير موجودة في جدول الأقسام، فسيمنعك قيد المفتاح الخارجي من القيام بذلك.
لنقم بإضافة قسمين، "تكنولوجيا المعلومات" و"الفنون"، إلى جدول الأقسام بالصيغة التالية استعلامات الإدراج:
INSERT INTO Departments VALUES(1, 'IT'); INSERT INTO Departments VALUES(2, 'Arts');
يجب أن تُضيف العبارتان قسمين إلى جدول الأقسام. يمكنك التأكد من إضافة القيمتين بتشغيل الاستعلام "SELECT * FROM Departments" بعد ذلك.
ثم حاول إدخال طالب جديد برقم قسم غير موجود في جدول الأقسام:
INSERT INTO Students(StudentName,DepartmentId) VALUES('John', 5);
لن يتم إدراج الصف، وستتلقى خطأً يقول: فشل قيد المفتاح الخارجي.
الفرق بين المفتاح الأساسي والمفتاح الأجنبي SQLite
تُساهم المفاتيح الأساسية والمفاتيح الخارجية في الحفاظ على سلامة البيانات، لكن لكل منهما دور مختلف. يُحدد المفتاح الأساسي الصفوف داخل جدول واحد، بينما يربط المفتاح الخارجي الصفوف بين جدولين مرتبطين. يُلخص الجدول أدناه الفروقات الرئيسية بينهما.
| قاعدة | المفتاح الأساسي | مفتاح غريب |
|---|---|---|
| الهدف | يُعرّف كل صف في جدوله الخاص بشكل فريد | يشير إلى المفتاح الأساسي لجدول آخر لربطهما |
| تميز | يجب أن تكون القيم فريدة | قد تتكرر القيم، لذا يمكن أن تشترك العديد من الصفوف الفرعية في أصل واحد. |
| القيم الفارغة | لا يمكن أن يكون فارغًا | يمكن أن تكون القيمة فارغة عندما تكون العلاقة اختيارية |
| عدد الطاولات | مفتاح أساسي واحد فقط لكل جدول | يمكن أن يحتوي الجدول على عدة مفاتيح خارجية |
| الفهرسة | تمت الفهرسة تلقائيًا | غير مفهرسة تلقائيًا؛ أضف واحدة لتحسين الأداء |
في مثال الطلاب والأقسام، يكون DepartmentId هو المفتاح الأساسي لجدول الأقسام ومفتاح خارجي في جدول الطلاب، وهو ما يربط كل طالب بقسم صالح.
SQLite المفتاح الأساسي المركب
المفتاح الأساسي المركب هو مفتاح أساسي يتكون من عمودين أو أكثر. يُستخدم عندما لا يكون أي عمود فريدًا بمفرده، ولكن تركيبة الأعمدة تكون فريدة لكل صف. SQLite يعامل القيم المجمعة كمفتاح واحد.
على سبيل المثال، قد يسمح جدول التسجيل للطالب نفسه في العديد من الدورات الدراسية، وللدورة الدراسية نفسها للعديد من الطلاب، ومع ذلك يجب أن يظهر كل زوج من الطالب والدورة الدراسية مرة واحدة فقط:
CREATE TABLE Enrollments ( StudentId INTEGER NOT NULL, CourseId INTEGER NOT NULL, Grade TEXT, PRIMARY KEY (StudentId, CourseId) );
هنا، لا يُعدّ كلٌّ من StudentId وCourseId فريدًا بمفرده، ولكن الزوج (StudentId, CourseId) فريد، لذا لا يمكن تسجيل الطالب نفسه في المقرر نفسه مرتين. يُرجى مراعاة النقاط التالية عند استخدام مفتاح مُركّب:
- استخدم مفتاحًا مركبًا عندما لا يستطيع عمود واحد تحديد صف بشكل فريد.
- كل عمود في المفتاح المركب يتبع قواعد المفتاح الأساسي، لذلك يجب أن تكون القيمة المجمعة فريدة وليست فارغة.
- يتم كتابة المفتاح المركب كبند PRIMARY KEY منفصل على مستوى الجدول، وليس داخل تعريف عمود واحد.
SQLite إجراءات المفتاح الخارجي: عند الحذف وعند التحديث
يمكن للمفتاح الخارجي أيضًا التحكم في ما يحدث للصفوف الفرعية عند حذف أو تحديث الصف الأصل الذي يشير إليه. تُضاف هذه الإجراءات المرجعية باستخدام عبارتي ON DELETE و ON UPDATE عند تعريف المفتاح الخارجي. SQLite يدعم خمسة إجراءات:
- لا يوجد إجراء — الإجراء الافتراضي، الذي يثير خطأً إذا كانت الصفوف الفرعية لا تزال تشير إلى الأصل.
- تقييد — يمنع الحذف أو التحديث فورًا، قبل تنفيذ أي تغيير آخر.
- تعيين NULL — يقوم بتعيين عمود المفتاح الخارجي الفرعي إلى قيمة فارغة.
- الوضع الإفتراضي — يقوم بتعيين عمود المفتاح الخارجي الفرعي إلى قيمته الافتراضية المعلنة.
- تتالي — يطبق نفس التغيير على صفوف الأبناء، لذا فإن حذف أحد الأبناء يؤدي إلى حذف أبنائه.
يُعيد المثال أدناه إنشاء جدول الطلاب بحيث يؤدي حذف قسم إلى حذف طلابه تلقائيًا، كما يؤدي تحديث معرف القسم إلى تحديث الطلاب المطابقين:
CREATE TABLE Students ( StudentId INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, StudentName NVARCHAR(50) NULL, DepartmentId INTEGER NOT NULL, FOREIGN KEY(DepartmentId) REFERENCES Departments(DepartmentId) ON DELETE CASCADE ON UPDATE CASCADE );
تذكر أن الإجراءات المرجعية لا تُنفذ إلا عند تفعيل دعم المفاتيح الخارجية، لذا قم بتشغيل الأمر PRAGMA foreign_keys = ON في بداية كل اتصال. بدون ذلك، SQLite يقوم بتحليل عبارات ON DELETE و ON UPDATE ولكنه لا يفرضها.



