MySQL / الأسس العلائقية و SQL الدقيقة / الدرس 1
التفكير العلائقي ومختبر المتجر
ابن نموذجاً دقيقاً للعملاء والطلبات والمنتجات وبنود الطلب التاريخية قبل كتابة التقارير.
في هذه الصفحة
أهداف الدرس
- اشرح الصفوف والمفاتيح المرشحة والخارجية وعددية العلاقات.
- اقرأ بيانات التدريب كاملة وتوقع أعداد صفوفها دون تنفيذها.
- ميّز افتراضات MySQL 8.4 عن ادعاءات التوافق مع MariaDB.
الصف يعبّر عن حقيقة واحدة
يحتاج متجر القرطاسية إلى حفظ هوية المشتري والمنتجات وأسعارها وقت الشراء. يمثّل الجدول نوعاً من الحقائق، ويمثّل الصف حالة واحدة منها، ويصف العمود خاصية. ينتمي الطلب إلى عميل واحد، ويمكن أن يملك العميل طلبات متعددة. ويضم الطلب منتجات عدة، ويظهر المنتج في طلبات كثيرة. لذلك يمثّل جدول order_items هذه العلاقة المتعددة الأطراف صراحة.
الهوية والحقيقة التاريخية
يعرّف المفتاح الأساسي الصف بصرف النظر عن اسمه المعروض. فقد تتكرر الأسماء، لذا تحمل الطلبات رقم العميل. ويسمح المفتاح المركب للبنود ببند واحد لكل منتج داخل الطلب. ويحفظ unit_price السعر المتفق عليه إذا تغيّر سعر الكتالوج غداً. أما إجمالي الطلب فهو ملخص مكرر مقصود؛ وسنتحقق لاحقاً من مطابقته للبنود بدلاً من افتراض تطابقهما الدائم.
الإعداد الاصطناعي الكامل
تستهدف الدورة سلسلة MySQL 8.4 LTS المدعومة، باستخدام InnoDB وأوضاع SQL الصارمة المعتادة ومنها ONLY_FULL_GROUP_BY. راجع إصدار التصحيح وتوافق العميل قبل أي تثبيت فعلي. يخص النص التالي قاعدة تدريب جديدة قابلة للحذف باسم mysql_course_lab فقط. ولا يتصل الدرس بخادم ولا ينفّذه. تفترض الأمثلة اللاحقة بقاء هذه الصفوف دون تغيير ما لم تعلن بيانات مستقلة. ولا نحتاج إلى بيانات عملاء حقيقية أو بيانات دخول.
CREATE DATABASE mysql_course_lab CHARACTER SET utf8mb4;
USE mysql_course_lab;
CREATE TABLE customers (
id INT PRIMARY KEY, name VARCHAR(80) NOT NULL,
email VARCHAR(120) NOT NULL UNIQUE, city VARCHAR(40) NULL
) ENGINE=InnoDB;
CREATE TABLE products (
id INT PRIMARY KEY, title VARCHAR(80) NOT NULL,
price DECIMAL(10,2) NOT NULL, stock INT NOT NULL,
CHECK (price >= 0), CHECK (stock >= 0)
) ENGINE=InnoDB;
CREATE TABLE orders (
id INT PRIMARY KEY, customer_id INT NOT NULL,
status VARCHAR(12) NOT NULL, placed_at DATETIME NOT NULL,
total DECIMAL(10,2) NOT NULL CHECK (total >= 0),
FOREIGN KEY (customer_id) REFERENCES customers(id)
) ENGINE=InnoDB;
CREATE TABLE order_items (
order_id INT NOT NULL, product_id INT NOT NULL,
quantity INT NOT NULL CHECK (quantity > 0),
unit_price DECIMAL(10,2) NOT NULL CHECK (unit_price >= 0),
PRIMARY KEY (order_id, product_id),
FOREIGN KEY (order_id) REFERENCES orders(id),
FOREIGN KEY (product_id) REFERENCES products(id)
) ENGINE=InnoDB;
INSERT INTO customers VALUES
(1,'Amina','amina@example.test','Cairo'),
(2,'Leo','leo@example.test','Lisbon'),
(3,'Noor','noor@example.test',NULL);
INSERT INTO products VALUES
(1,'Notebook',10.00,20),(2,'Pen',2.50,100),(3,'Bag',30.00,5);
INSERT INTO orders VALUES
(101,1,'paid','2026-01-10 10:00:00',25.00),
(102,1,'new','2026-01-11 11:00:00',30.00),
(103,2,'paid','2026-01-12 12:00:00',10.00);
INSERT INTO order_items VALUES
(101,1,2,10.00),(101,2,2,2.50),(102,3,1,30.00),(103,1,1,10.00);
أنشئ جداول الآباء قبل الأبناء، وأدخل صفوف الآباء قبل المراجع الخارجية. تضم البيانات ثلاثة عملاء وثلاثة منتجات وثلاثة طلبات وأربعة بنود. ويبلغ مجموع بندي الطلب 101 مقدار 2 × 10.00 + 2 × 2.50 = 25.00. وتتيح المعرّفات الصريحة استنتاج النتائج التالية بدقة.
افحص المعنى قبل الحجم
يجيب سعر الكتالوج وسعر البند التاريخي عن سؤالين مختلفين. والمدينة المفقودة معلومة مجهولة تمثلها SQL NULL، وليست سلسلة فارغة ولا النص NULL. تحمي المفاتيح والقيود العلاقات حتى عندما تكتب تطبيقات متعددة بالتزامن. لكنها لا تثبت ملكية البريد لشخص ولا وقوع الدفع؛ فهاتان عمليتان تجاريتان تحتاجان إلى أدلة خارج النموذج العلائقي المصغر.
SELECT id, name, city FROM customers ORDER BY id;
id | name | city
1 | Amina | Cairo
2 | Leo | Lisbon
3 | Noor | NULL
ينتج الترتيب الصريح Amina ثم Leo ثم Noor، وتحمل مدينة Noor قيمة SQL NULL. وبدون ORDER BY لا يضمن الخادم ترتيباً، حتى لو استخدم فهرس المفتاح الأساسي. فالجدول علاقة وليس ورقة عمل ذات مواقع صفوف دائمة.
اعرف الخادم الفعلي
يشترك MySQL و MariaDB في أصل SQL، لكن لهما إصدارات ومحسنات ومصادقة وتنفيذ JSON وتفاصيل نسخ متماثل مختلفة. لا تعتبر رقم إصدار MariaDB دليلاً على سلوك MySQL 8.4. تعلّم النموذج هنا ثم تحقق من الصياغة الخاصة بالمورّد في دليل الخادم الفعلي. الأمثلة مواد تعليمية غير قابلة للتنفيذ داخل المنصة، ونتائجها مستنتجة من البيانات وليست قياسات من اتصال إنتاجي خفي.
الأخطاء الشائعة وإصلاحها
هوية مكررة: ERROR 1062 (23000).
- لماذا يحدث؟
- إعادة رقم العميل 1 تصطدم بالمفتاح الأساسي.
- كيف تصلحه؟
- اختر رقماً جديداً فعلاً أو حدّث العميل الحالي عن قصد.
- كيف تتجنب تكراره؟
- افصل تخصيص الهوية عن الأسماء وتحقق من خرائط الاستيراد.
أب مفقود: ERROR 1452 (23000).
- لماذا يحدث؟
- يشير الطلب إلى العميل 99 غير الموجود.
- كيف تصلحه؟
- أنشئ الأب الصحيح أولاً أو أصلح المرجع الخاطئ.
- كيف تتجنب تكراره؟
- حمّل الجداول حسب العلاقات وأبق فحص المفاتيح الخارجية مفعّلاً.
تنفيذ الإعداد مرتين: ERROR 1007 (HY000).
- لماذا يحدث؟
- قاعدة التدريب المسماة موجودة بالفعل.
- كيف تصلحه؟
- استخدم مختبراً مستقلاً باسم آخر بعد مراجعة المحتوى.
- كيف تتجنب تكراره؟
- اعتبر الإعداد نصاً ينفذ مرة واحدة ولا تحذف قاعدة مجهولة.
اختبر فهمك
1. لماذا لا تخزّن الطلبات قائمة أرقام منتجات مفصولة بفواصل؟
اعرض الحل المشروح
يحتاج كل منتج إلى كميته وسعره التاريخي، ويجب أن تتحقق المفاتيح الخارجية من كل مرجع منفرد. تعبّر صفوف order_items الأربعة عن هذه الحقائق المستقلة. أما القائمة النصية فتحتاج إلى تحليل وتُصعّب فرض التفرد والسلامة.
2. توقع أرقام طلبات العميل 1 واشرح العلاقة.
اعرض الحل المشروح
يحمل الطلبان 101 و 102 القيمة customer_id = 1. يعبّر المرجع المشترك عن طلبات متعددة لعميل واحد ولا يكرر صف العميل. ويظل العميل 3 موجوداً رغم عدم امتلاكه طلبات، وهو ما سنستخدمه عند دراسة الربط الخارجي.
أهم ما تعلمته
- نمذج الحقائق والعلاقات قبل اختيار الاستعلام.
- استخدم المفاتيح للهوية والأعمدة التاريخية لحفظ الماضي.
- استخدم بيانات التدريب فقط واشترط ORDER BY لكل ترتيب مضمون.