SQLite / الأساسي: المحرك المضمّن والبيانات الصحيحة / الدرس 3
المفاتيح والقيود وفرض العلاقات الخارجية
نمذج الهوية والعلاقات بقواعد مفاتيح SQLite وقابلية غياب صريحة وفحوص وفرض علاقات خارجية متحقق منه لكل اتصال.
في هذه الصفحة
أهداف الدرس
- فصل هوية الصف من تفرد العمل.
- تمكين العلاقات الخارجية والتحقق منها.
- تفسير فشل القيد كدليل على العقد.
اختر المفتاح من تعريف الكيان
يحدد المفتاح الأساسي الصف، ويمكن لـ UNIQUE حماية معرف تجاري آخر. قد يملك العميل رقماً داخلياً ورمز حساب خارجي فريداً، وهما عقدان مختلفان. يكون INTEGER PRIMARY KEY بالصياغة الدقيقة اسماً بديلاً لـ rowid في جدوله، مع استثناءات موثقة مثل صياغة التنازل. ليست INT PRIMARY KEY التصريح نفسه.
لا تنقل صياغة الترقيم من محرك آخر. قد يولد حذف قيمة INTEGER PRIMARY KEY معرفاً دون AUTOINCREMENT. تضيف الأخيرة كلفة وغاية أضيق لمنع إعادة استخدام معينة، ولا تلزم للهوية المعتادة ولا تعد بفواتير بلا فجوات. افصل المعرف المستقر عن سياسة الترقيم التجارية.
احم المطلوب والثوابت المحلية
ترفض NOT NULL المفقود وترفض CHECK الشرط الخاطئ وتمنع UNIQUE تكرار المفتاح وفق مقارنة قيمه. لا تعتبر CHECK النتيجة NULL خاطئة، لذلك اجمع إيجابية الكمية مع NOT NULL. لقابلية غياب المفاتيح العادية استثناءات تاريخية؛ تجنب الافتراض بإعلان المطلوب أو تصميم STRICT أو WITHOUT ROWID مناسب.
يحمي المثال رمزاً مطلوباً وكمية موجبة، ويظهر الصف الصحيح الحالة المقصودة بدلاً من فشل متعمد أثناء التهيئة. يجب أن يميز المستدعي رفض القيد من الإدراج الناجح وألا يعلن دواماً قبل اكتمال المعاملة. اربط معلومات الخطأ المستقرة باستجابة مجال دون كشف الداخل.
CREATE TABLE product(id INTEGER PRIMARY KEY, code TEXT NOT NULL UNIQUE,
quantity INTEGER NOT NULL CHECK(quantity>0)) STRICT;
INSERT INTO product(code,quantity) VALUES('P-01',3);
SELECT id,code,quantity FROM product ORDER BY id;
id|code|quantity
1|P-01|3
يحصل المفتاح المحذوف على 1 في هذا الجدول الجديد وتحفظ القيود ثابت الصف.
فعّل الفرض في كل اتصال قبل العمل
تصف FOREIGN KEY العلاقة، لكن يجب تمكين فرضها والتحقق منه في الاتصال الفعلي بـ PRAGMA foreign_keys. لا تفترض أن إطاراً أو اتصالاً آخر أو صدفة فعل ذلك لهذا الاتصال. لا يعمل تبديلها داخل معاملة كإعداد فوري عادي؛ حدد السياسة قبل بدء العمل المرتبط.
يفعل المثال الفرض قبل إنشاء جدولي التدريب واستخدامهما. يشير الطلب إلى العميل 1 ويؤكد الربط العلاقة. يجب أن يحقق مفتاح الأب شروط التفرد وترتيب المحارف. افهرس مفتاح الابن عند مبرر الأداء؛ فلا ينشئ إعلان العلاقة تلقائياً كل فهرس مفيد في جهتها.
PRAGMA foreign_keys=ON;
CREATE TABLE customer(id INTEGER PRIMARY KEY, name TEXT NOT NULL);
CREATE TABLE purchase(id INTEGER PRIMARY KEY, customer_id INTEGER NOT NULL
REFERENCES customer(id));
INSERT INTO customer VALUES(1,'Amina');
INSERT INTO purchase VALUES(10,1);
SELECT p.id,c.name FROM purchase AS p JOIN customer AS c
ON c.id=p.customer_id ORDER BY p.id;
PRAGMA foreign_keys;
id|name
10|Amina
foreign_keys
1
يرتبط الطلب بأمينة ويبلغ pragma الأخير 1 لهذا الاتصال دون مخطط خارجي.
حدد الحذف والاختيارية بقصد
قد يمثل مفتاح ابن يقبل NULL علاقة اختيارية، وتحتاج المطلوبة NOT NULL أيضاً. تعبر RESTRICT و SET NULL و CASCADE عند الحذف عن سياسات مختلفة. ليس التسلسل مجرد وسيلة لإسكات خطأ؛ فقد يزيل بيانات تابعة كثيرة. راجع الاحتفاظ والتدقيق قبل اختياره.
قد تسمح علاقة مؤجلة بعدم اتساق مؤقت داخل المعاملة يجب إصلاحه عند نقطة الفحص المطلوبة، لا تثبيت صف يتيم. تفحص foreign_key_check المخالفات، وتختلف عن integrity_check التي لا تغني عنها. ولا يثبت نجاح إنشاء المخطط توافق البيانات الموجودة مع كل علاقة مقصودة.
اختبر القبول والرفض للانتقالات
أنشئ لكل قيد اختبار قبول وآخر رفض دون بقايا حالة عمل جزئية. اختبر تكرار الرمز وغياب المطلوب والكمية غير الموجبة والأب المفقود وحذف أب له أبناء. يملك صاحب المعاملة قرار التراجع وكيفية عرض الرفض، لا مجرد متابعة بقية العبارات رغم الخطأ.
اجعل قيود المخطط وتحقق التطبيق متفقين. توفر الواجهة رسالة مفيدة وتحمي القاعدة الاستيراد والكتّاب الآخرين أيضاً. لا تعطل العلاقات أو تحذف UNIQUE لمجرد مخالفة البيانات الحالية. افحص الأصل وأصلحه بعملية مراجعة وتحقق من الثابت قبل توسيع الوصول.
الأخطاء الشائعة وإصلاحها
FOREIGN KEY constraint failed
- لماذا يحدث؟
- غاب الأب أو خالفت عملية عليه العلاقة.
- كيف تصلحه؟
- افحص المفاتيح وطبق سياسة المعاملة والحذف المقصودة.
- كيف تتجنب تكراره؟
- فعّل الفرض واختبر الأب المفقود.
UNIQUE constraint failed
- لماذا يحدث؟
- تكررت قيمة مفتاح تجاري أو أساسي.
- كيف تصلحه؟
- ارفض أو صالح التكرار بسياسة طلب صريحة.
- كيف تتجنب تكراره؟
- اختبر التكرار وتطبيع المفتاح.
قبل CHECK كمية مفقودة.
- لماذا يحدث؟
- اختلط تقييم NULL بالشرط الخاطئ.
- كيف تصلحه؟
- أضف NOT NULL للمطلوب.
- كيف تتجنب تكراره؟
- اختبر المفقود والصفر والسالب منفصلة.
اختبر فهمك
1. هل يثبت إعلان REFERENCES customer(id) أن كل اتصال تطبيق يفرض العلاقة؟
اعرض الحل المشروح
لا؛ فعّل PRAGMA foreign_keys وافحص نتيجته في كل اتصال معني قبل بدء المعاملات. اختبر إشارة إلى أب غير موجود في قاعدة معزولة. يصف الإعلان العلاقة، أما فرضها النشط فسياسة اتصال مستقلة ينبغي التحقق منها، لا افتراض أن إطاراً أو أداة أخرى اختارتها نيابة عنه.
2. لماذا لا توفر AUTOINCREMENT حلاً لفواتير بلا فجوات؟
اعرض الحل المشروح
تغير إعادة استخدام rowid وتضيف أعمال متابعة، لكنها لا تلغي فجوات قد تتركها عمليات غير ناجحة أو أحداث عمر البيانات. يحتاج ترقيم الفواتير عملية عمل منفصلة بقواعد احتفاظ وتزامن معلنة. لا تمنح هوية الصف العادية ذلك الضمان تلقائياً بمجرد اختيار الكلمة.
أهم ما تعلمته
- تحمي المفاتيح الهوية والتفرد بقواعد SQLite المحددة.
- فرض العلاقة سياسة اتصال متحقق منها.
- تكمل قابلية الغياب والحذف والمعاملة عقد العلاقة.