We are still cooking the magic in the way!
MySQL وتصميم قواعد البيانات
التطبيع - 1NF و 2NF
التطبيع - 1NF و 2NF
التطبيع هو عملية تنظيم جداول قاعدة البيانات لتقليل التكرار وتحسين سلامة البيانات. في هذا الدرس، سنستكشف الشكلين الطبيعيين الأولين ونتعلم كيفية تطبيقهما على تصميم قاعدة البيانات الخاصة بك.
ما هو التطبيع ولماذا نطبّع؟
التطبيع هو نهج منظم لتفكيك الجداول للقضاء على تكرار البيانات والخصائص غير المرغوبة مثل شذوذات الإدراج والتحديث والحذف.
الهدف الرئيسي: التطبيع يضمن أن كل جزء من البيانات يُخزَّن في مكان واحد بالضبط، مما يجعل قاعدة بياناتك أكثر كفاءة وأسهل للصيانة.
فوائد التطبيع:
✓ يلغي تكرار البيانات
- لا معلومات مكررة
- يوفر مساحة التخزين
- يقلل التناقضات
✓ يحسن سلامة البيانات
- مصدر واحد للحقيقة
- أسهل لفرض القيود
- أخطاء تحديث أقل
✓ يبسط الصيانة
- التغييرات تُجرى في مكان واحد
- منطق تحديث أقل تعقيداً
- خطر أخطاء منخفض
✓ أداء استعلام أفضل
- أحجام جداول أصغر
- فهارس أكثر كفاءة
- عمليات بحث أسرع
فهم الشذوذات
قبل التطبيع، تعاني قواعد البيانات غالباً من ثلاثة أنواع من الشذوذات:
❌ مثال: جدول طلاب غير محسّن
CREATE TABLE students_bad (
student_id INT,
student_name VARCHAR(100),
courses VARCHAR(200),
instructors VARCHAR(200),
departments VARCHAR(200)
);
INSERT INTO students_bad VALUES
(1, 'John', 'Math,Physics', 'Dr. Smith,Dr. Jones', 'Science,Science'),
(2, 'Jane', 'Math', 'Dr. Smith', 'Science');
المشاكل:
1. قيم متعددة مخزنة في أعمدة واحدة (ينتهك 1NF)
2. صعوبة الاستعلام عن دورات محددة
3. لا يمكن إضافة دورة جديدة بدون طالب
4. تحديث اسم المدرس يتطلب تغييرات متعددة
أنواع الشذوذات
1. شذوذ الإدراج
المشكلة: لا يمكن إضافة بيانات بدون إضافة بيانات غير متعلقة
مثال: لا يمكن إضافة دورة جديدة ما لم يسجل طالب
2. شذوذ التحديث
المشكلة: يجب تحديث البيانات في أماكن متعددة
مثال: إذا تغير اسم المدرس، يجب تحديث جميع سجلات الطلاب
3. شذوذ الحذف
المشكلة: حذف البيانات يسبب فقدان بيانات أخرى غير متعلقة
مثال: إذا ترك آخر طالب دورة، نفقد معلومات الدورة
تأثير في العالم الحقيقي: كان لدى موقع تجارة إلكترونية كبير أسماء المنتجات مخزنة مع كل طلب. عندما أصلحوا خطأ إملائي في اسم منتج، آلاف الطلبات السابقة لا تزال تظهر الإملاء القديم!
الشكل الطبيعي الأول (1NF)
الجدول في الشكل الطبيعي الأول إذا كان يستوفي هذه القواعد:
قواعد 1NF:
1. كل عمود يحتوي على قيم ذرية
- لا قيم متعددة في خلية واحدة
- لا قوائم مفصولة بفواصل
- لا مصفوفات أو مجموعات
2. كل عمود يحتوي على قيم من نفس النوع
- جميع القيم في عمود لها نفس نوع البيانات
- تنسيق متسق
3. كل عمود له اسم فريد
- لا أسماء أعمدة مكررة
- أسماء واضحة وصفية
4. ترتيب الصفوف لا يهم
- النتائج يجب أن تكون نفسها بغض النظر عن ترتيب الصف
- استخدم ORDER BY للفرز، وليس الترتيب الفيزيائي
التحويل إلى 1NF
لنصلح جدول الطلاب ليتوافق مع 1NF:
❌ ليس في 1NF (قيم متعددة في الخلايا):
CREATE TABLE students_bad (
student_id INT,
student_name VARCHAR(100),
courses VARCHAR(200) -- ❌ يخزن "Math,Physics,Chemistry"
);
✓ في 1NF (قيم ذرية):
CREATE TABLE students (
student_id INT,
student_name VARCHAR(100),
course VARCHAR(100) -- ✓ قيمة واحدة لكل خلية
);
INSERT INTO students VALUES
(1, 'John', 'Math'),
(1, 'John', 'Physics'),
(1, 'John', 'Chemistry'),
(2, 'Jane', 'Math');
النتيجة:
- كل خلية تحتوي على قيمة واحدة بالضبط
- لا قوائم مفصولة بفواصل
- البيانات الآن قابلة للاستعلام والصيانة
اختبار سريع: إذا كنت بحاجة لاستخدام LIKE '%value%' أو دوال السلسلة للعثور على البيانات، فمن المحتمل أنك تنتهك 1NF.
مثال 1NF: طلبات التجارة الإلكترونية
❌ ليس في 1NF:
CREATE TABLE orders_bad (
order_id INT PRIMARY KEY,
customer_name VARCHAR(100),
products VARCHAR(500), -- "Laptop,Mouse,Keyboard"
quantities VARCHAR(100) -- "1,2,1"
);
✓ في 1NF:
CREATE TABLE orders (
order_id INT,
customer_name VARCHAR(100),
product VARCHAR(100),
quantity INT,
PRIMARY KEY (order_id, product)
);
INSERT INTO orders VALUES
(1001, 'Alice', 'Laptop', 1),
(1001, 'Alice', 'Mouse', 2),
(1001, 'Alice', 'Keyboard', 1);
الفوائد:
- سهولة الاستعلام: SELECT SUM(quantity) FROM orders WHERE product = 'Mouse'
- سهولة التحديث: UPDATE orders SET quantity = 3 WHERE product = 'Mouse'
- لا حاجة للتحليل
الشكل الطبيعي الثاني (2NF)
الجدول في الشكل الطبيعي الثاني إذا:
قواعد 2NF:
1. يجب أن يكون في 1NF
- جميع قواعد 1NF محققة
2. لا توابع جزئية
- كل عمود غير مفتاحي يجب أن يعتمد على المفتاح الأساسي بالكامل
- ينطبق فقط على الجداول بمفاتيح مركبة
- السمات غير المفتاحية لا يمكن أن تعتمد على جزء من المفتاح
فهم التوابع الجزئية
التابع الجزئي يحدث عندما يعتمد عمود غير مفتاحي على جزء فقط من مفتاح أساسي مركب.
❌ ليس في 2NF (لديه تابع جزئي):
CREATE TABLE order_details (
order_id INT,
product_id INT,
customer_name VARCHAR(100), -- ❌ يعتمد فقط على order_id
customer_email VARCHAR(100), -- ❌ يعتمد فقط على order_id
product_name VARCHAR(100), -- ❌ يعتمد فقط على product_id
product_price DECIMAL(10,2), -- ❌ يعتمد فقط على product_id
quantity INT, -- ✓ يعتمد على كلا المفتاحين
PRIMARY KEY (order_id, product_id)
);
المشاكل:
- customer_name يعتمد فقط على order_id (وليس product_id)
- product_name يعتمد فقط على product_id (وليس order_id)
- هذا يخلق تكراراً وشذوذات
التحويل إلى 2NF
للتحويل إلى 2NF، افصل الأعمدة التابعة جزئياً إلى جداولها الخاصة:
✓ في 2NF (لا توابع جزئية):
-- معلومات العميل تعتمد فقط على الطلب
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_name VARCHAR(100),
customer_email VARCHAR(100),
order_date DATE
);
-- معلومات المنتج تعتمد فقط على المنتج
CREATE TABLE products (
product_id INT PRIMARY KEY,
product_name VARCHAR(100),
product_price DECIMAL(10,2),
stock_quantity INT
);
-- جدول التقاطع - فقط الأعمدة التي تعتمد على كلا المفتاحين
CREATE TABLE order_items (
order_id INT,
product_id INT,
quantity INT,
price_at_purchase DECIMAL(10,2),
PRIMARY KEY (order_id, product_id),
FOREIGN KEY (order_id) REFERENCES orders(order_id),
FOREIGN KEY (product_id) REFERENCES products(product_id)
);
الفوائد:
- لا تكرار: customer_name مخزن مرة واحدة لكل طلب
- لا شذوذات تحديث: تغيير سعر المنتج لا يؤثر على الطلبات القديمة
- فصل واضح للمسؤوليات
مهم: الجداول بمفاتيح أساسية ذات عمود واحد تحقق تلقائياً 2NF لأنه لا يمكن أن تكون هناك توابع جزئية!
مثال عملي 2NF: التسجيل في الدورة
❌ ليس في 2NF:
CREATE TABLE enrollment_bad (
student_id INT,
course_id INT,
student_name VARCHAR(100), -- تابع جزئي على student_id
student_email VARCHAR(100), -- تابع جزئي على student_id
course_name VARCHAR(100), -- تابع جزئي على course_id
instructor VARCHAR(100), -- تابع جزئي على course_id
grade VARCHAR(2), -- تابع كامل ✓
enrollment_date DATE, -- تابع كامل ✓
PRIMARY KEY (student_id, course_id)
);
✓ في 2NF:
CREATE TABLE students (
student_id INT PRIMARY KEY,
student_name VARCHAR(100),
student_email VARCHAR(100)
);
CREATE TABLE courses (
course_id INT PRIMARY KEY,
course_name VARCHAR(100),
instructor VARCHAR(100),
credits INT
);
CREATE TABLE enrollments (
student_id INT,
course_id INT,
grade VARCHAR(2),
enrollment_date DATE,
PRIMARY KEY (student_id, course_id),
FOREIGN KEY (student_id) REFERENCES students(student_id),
FOREIGN KEY (course_id) REFERENCES courses(course_id)
);
اختبار 1NF و 2NF
قائمة التحقق من 1NF:
□ لا مجموعات متكررة أو مصفوفات
□ كل خلية تحتوي على قيمة واحدة بالضبط
□ جميع الإدخالات في عمود من نفس النوع
□ كل عمود له اسم فريد
□ كل صف فريد (له مفتاح أساسي)
قائمة التحقق من 2NF:
□ الجدول في 1NF
□ الجدول له مفتاح أساسي محدد
□ إذا كان هناك مفتاح مركب:
□ جميع الأعمدة غير المفتاحية تعتمد على المفتاح بالكامل
□ لا عمود يعتمد على جزء فقط من المفتاح
□ إذا كان مفتاح عمود واحد: تلقائياً في 2NF
تمرين تطبيقي:
حدد المشاكل وحوّل إلى 2NF:
CREATE TABLE project_assignments (
employee_id INT,
project_id INT,
employee_name VARCHAR(100),
department VARCHAR(50),
project_name VARCHAR(100),
project_budget DECIMAL(12,2),
hours_worked INT,
PRIMARY KEY (employee_id, project_id)
);
الحل:
المشاكل:
- employee_name، department يعتمدان فقط على employee_id (جزئي)
- project_name، project_budget يعتمدان فقط على project_id (جزئي)
حل 2NF:
CREATE TABLE employees (
employee_id INT PRIMARY KEY,
employee_name VARCHAR(100),
department VARCHAR(50)
);
CREATE TABLE projects (
project_id INT PRIMARY KEY,
project_name VARCHAR(100),
project_budget DECIMAL(12,2)
);
CREATE TABLE assignments (
employee_id INT,
project_id INT,
hours_worked INT,
PRIMARY KEY (employee_id, project_id),
FOREIGN KEY (employee_id) REFERENCES employees(employee_id),
FOREIGN KEY (project_id) REFERENCES projects(project_id)
);
الملخص
في هذا الدرس، تعلمت:
- التطبيع يلغي التكرار ويمنع شذوذات البيانات
- 1NF يتطلب قيماً ذرية - لا قيم متعددة في خلية واحدة
- 1NF يلغي المجموعات المتكررة ويضمن أن كل خلية لها قيمة واحدة
- 2NF يلغي التوابع الجزئية على المفاتيح المركبة
- 2NF يتطلب أن تعتمد جميع الأعمدة غير المفتاحية على المفتاح الأساسي بالكامل
- الجداول بمفاتيح أعمدة واحدة تحقق تلقائياً 2NF
التالي: في الدرس التالي، سنواصل مع الشكل الطبيعي الثالث (3NF) وشكل Boyce-Codd الطبيعي (BCNF)!