حذف البيانات باستخدام DELETE في الـ SQL
السلام عليكم ورحمة الله وبركاته
المقدمة
لقد تعلمنا في المقالات السابقة الأوامر الأساسية للتعامل مع قواعد البيانات مثل CREATE و INSERT و UPDATE
والآن تبقى لنا تعلم كيفية حذف البيانات من الجداول باستخدام أمر DELETE
لنكمل معًا الأوامر الأساسية في الـ SQL الخاصة بالـ DML وهى كما ذكرنا سابقاً:
CREATEلإنشاء الجداولINSERTلإضافة البياناتSELECTلقراءة البياناتUPDATEلتعديل البياناتDELETEلحذف البيانات
وبعض الأوامر الأخرى التي ستتعرف عليها لاحقًا
الشيء المهم الآن أننا في هذه المقالة سنتعلم كيفية حذف البيانات من الجداول باستخدام أمر DELETE
وهذا الأمر من أخطر الأوامر في الـ SQL لأنه يمكن أن يمحو بيانات مهمة نهائيًا دون إمكانية استرجاعها
لذا بمجرد ما تقوم بحذف بيانات باستخدام DELETE، فإنها تختفي للأبد
لذلك يجب أن تكون حذرًا جدًا عند استخدام هذا الأمر، هو والأوامر المشابهة له مثل TRUNCATE و DROP
لا داعي لأن اجعلك تتخيل أنك إذا كنت تدير نظام إدارة طلاب وتريد حذف طالب واحد، لكن بسبب خطأ بسيط تحذف جميع الطلاب
أو تخيل أنك تدير متجر إلكتروني وتريد حذف منتج واحد، لكن تحذف جميع المنتجات بالخطأ وهكذا
لذا في معظم المشاريع لا يتم استخدام أمر DELETE في معظم الحالات
بل يتم استخدام شيء يدعى Soft Delete حيث يتم وضع علامة على البيانات على أنها محذوفة دون حذفها فعليًا من الجدول
وسنرى كيف يتم ذلك لاحقًا في هذه المقالة
ما هو أمر الـ DELETE ؟
أمر الـ DELETE يستخدم لـ حذف البيانات نهائيًا من الجداول
وهو أمر لا يمكن التراجع عنه في معظم الحالات، فبمجرد حذف البيانات تختفي للأبد ولهذا نسميه بالـ Hard Delete
ومثله مثل الـ UPDATE عندما قلنا أنه يمكن أن يكون خطيرًا إذا لم لم نستخدمه مع الـ WHERE
وقلنا أنك مع الـ UPDATE إذا لم تستخدم WHERE ستقوم بتحديث جميع البيانات في الجدول
نفس الشيء مع الـ DELETE، إذا لم تستخدم WHERE ستقوم بحذف جميع البيانات في الجدول في لحظة واحدة دون رجعة وأيضًا سيتم فصلك من الشركة التي تعمل بها غالبًا
لذا يتم استخدامم شرط الـ WHERE دائمًا مع أمر الـ DELETE لتحديد الصفوف التي تريد حذفها بناءًا على شروط معينة
هذا الشرط هو الذي يحدد الصفوف التي سيتم حذفها، وإذا لم تستخدمه، سيتم حذف كل الصفوف في الجدول
وينصح دائمًا باستخدام SELECT قبل تنفيذ DELETE للتأكد من الصفوف التي سيتم حذفها
وعلى أي حال استخدم أمر DELETE بحذر شديد، ولا تستخدمه إلا إذا كنت متأكدًا من أنك تريد حذف البيانات نهائيًا
وبالطبع هناك أوامر أخرى مثل TRUNCATE و DROP التي تستخدم أيضًا لحذف البيانات، لكن لكل منها استخداماته الخاصة
وسنعرض أمثلة على هذه الأوامر في هذه المقالة
تجهيز الجدول للأمثلة العملية
كالعادة قبل أن نبدأ، أحتاج لتذكيركم بشكل جدول الـ Students الذي سنستخدمه في هذه المقالة
والبيانات التي يحتويه من المقالات السابقة
+----+-----------------+------+--------------+--------------------------+
| id | name | age | level | email |
+----+-----------------+------+--------------+--------------------------+
| 1 | Ahmed Moustafa | 21 | Intermediate | ahmed@university.edu |
| 2 | Osama Ali | 21 | Intermediate | osama.ali@university.edu |
| 3 | Mohamed Adel | 23 | Advanced | mohamed@university.edu |
| 4 | Kamal Mahmoud | 22 | Advanced | kamal@university.edu |
| 5 | Ayman Hassan | 21 | Advanced | ayman@university.edu |
| 6 | Adam Ibrahim | NULL | Beginner | adam@university.edu |
| 7 | Ismail Khaled | 23 | Advanced | ismail@university.edu |
| 8 | Ali Hassan | NULL | NULL | ali@university.edu |
| 9 | test student 1 | NULL | NULL | test1@university.edu |
| 10 | test student 2 | NULL | NULL | test2@university.edu |
| 11 | test student 3 | NULL | NULL | test3@university.edu |
| 12 | test student 4 | NULL | NULL | test4@university.edu |
+----+-----------------+------+--------------+--------------------------+
هذه البيانات التي سنستخدمها في جميع الأمثلة
لاحظ أنني أضفت بعض الطلاب الاختباريين مثل test student 1 و test student 2 و test student 3 و test student 4
لكي نقوم بحذفهم في بعض الأمثلة
الآن دعونا نبدأ في تعلم كيفية استخدام أمر DELETE لحذف البيانات من هذا الجدول
الشكل الأساسي لأمر DELETE
أمر DELETE كما قلنا يستخدم لحذف البيانات من الجداول
ونحن نستخدم معه الـ WHERE لتحديد الصفوف التي نريد حذفها بناءً على شروط معينة كما ذكرنا سابقًا
لنفترض أننا نريد حذف الطالب test student 1 صاحب الـ id رقم 9 من جدول Students
يمكننا استخدام الأمر التالي:
DELETE FROM Students
WHERE id = 9;
دعونا نفهم جزء كما اعتدنا:
DELETE FROM Students: هذا يعني أننا نريد حذف بيانات من جدولStudentsWHERE id = 9: هذا يعني أننا نريد حذف الصف الذي يكون فيهidيساوي9
هكذا نكون قد حددنا الصف الذي نريد حذفه بدقة عن طريق استخدام WHERE
وبعد تنفيذ هذا الأمر، سيتم حذف الطالب test student 1 نهائيًا من الجدول دون إمكانية استرجاعه
+----+-----------------+------+--------------+--------------------------+
| id | name | age | level | email |
+----+-----------------+------+--------------+--------------------------+
| 1 | Ahmed Moustafa | 21 | Intermediate | ahmed@university.edu |
| 2 | Osama Ali | 21 | Intermediate | osama.ali@university.edu |
| 3 | Mohamed Adel | 23 | Advanced | mohamed@university.edu |
| 4 | Kamal Mahmoud | 22 | Advanced | kamal@university.edu |
| 5 | Ayman Hassan | 21 | Advanced | ayman@university.edu |
| 6 | Adam Ibrahim | NULL | Beginner | adam@university.edu |
| 7 | Ismail Khaled | 23 | Advanced | ismail@university.edu |
| 8 | Ali Hassan | NULL | NULL | ali@university.edu |
| 10 | test student 2 | NULL | NULL | test2@university.edu |
| 11 | test student 3 | NULL | NULL | test3@university.edu |
| 12 | test student 4 | NULL | NULL | test4@university.edu |
+----+-----------------+------+--------------+--------------------------+
خطر عدم استخدام WHERE
تذكر أن تستخدم WHERE دائمًا لتحديد الصفوف التي تريد حذفها بدقة
لأنك إذا لم تستخدم WHERE وكتبت الأمر كالتالي:
DELETE FROM Students;
هذا الأمر سيحذف جميع البيانات في الجدول Students
وهذا هو الخطر الذي يجب أن تتجنبه دائمًا لأنك حينها لن تستطيع استرجاع البيانات المحذوفة
وكما قلنا سابقًا، هذا الأمر هو من أخطر الأوامر في الـ SQL ويضمن لك الفصل من الشركة التي تعمل بها
كيف تتجنب الأخطاء عند استخدام DELETE
حسنًا، لنفترض الآن أنه مطلوب أن نقوم بحذف أي طالب ليس لديه age و level
بمعنى أن نمسح الطلاب الذين لديهم NULL في كلا العمودين الـ age و level
هنا أول شيء هو عدم استخدام DELETE مباشرةً، بل يجب أن نتأكد من الصفوف التي سنحذفها أولاً
لذا سنستخدم SELECT مع الـ WHERE للتحقق من الصفوف التي سنحذفها
SELECT * FROM Students WHERE age IS NULL OR level IS NULL;
لنرى النتائج:
+----+-----------------+------+--------------+--------------------------+
| id | name | age | level | email |
+----+-----------------+------+--------------+--------------------------+
| 6 | Adam Ibrahim | NULL | Beginner | adam@university.edu |
| 8 | Ali Hassan | NULL | NULL | ali@university.edu |
| 10 | test student 2 | NULL | NULL | test2@university.edu |
| 11 | test student 3 | NULL | NULL | test3@university.edu |
| 12 | test student 4 | NULL | NULL | test4@university.edu |
+----+-----------------+------+--------------+--------------------------+
هل هذه هي الصفوف التي نريد حذفها ؟
ستلاحظ أننا نريد حذف أي طالب ليس لديه age و level
أي يجب أن يكون كلا العمودين NULL
لذا إذا نظرنا إلى النتائج، سنجد أن الطالب Adam Ibrahim لديه age لكن ليس لديه level
وهذا ما لا نريده
الخطأ حصل لأننا كتبنا شرط الـ WHERE كالتالي:
WHERE age IS NULL OR level IS NULL;
وليس كالتالي:
WHERE age IS NULL AND level IS NULL;
لقد استخدمنا OR بدلاً من AND
تخيل لو قمنا بتنفيذ DELETE بهذا الشرط مباشرةً دون التأكد من النتائج أولاً
كان سيحذف الطالب Adam Ibrahim أيضًا رغم أنه ليس لدينا مشكلة معه
لذا يجب عليك دائمًا التأكد من النتائج بإستخدام SELECT قبل تنفيذ DELETE
الآن دعنا نستخدم الشرط الصحيح:
SELECT * FROM Students WHERE age IS NULL AND level IS NULL;
لنرى النتائج:
+----+-----------------+------+--------------+--------------------------+
| id | name | age | level | email |
+----+-----------------+------+--------------+--------------------------+
| 8 | Ali Hassan | NULL | NULL | ali@university.edu |
| 10 | test student 2 | NULL | NULL | test2@university.edu |
| 11 | test student 3 | NULL | NULL | test3@university.edu |
| 12 | test student 4 | NULL | NULL | test4@university.edu |
+----+-----------------+------+--------------+--------------------------+
الآن هذه هي الصفوف التي نريد حذفها بالفعل
لذا يمكننا تنفيذ أمر DELETE كالتالي بنفس شرط الـ WHERE:
DELETE FROM Students
WHERE age IS NULL AND level IS NULL;
وبعد تنفيذ هذا الأمر، سيتم حذف الطلاب الذين ليس لديهم age و level
+----+-----------------+------+--------------+--------------------------+
| id | name | age | level | email |
+----+-----------------+------+--------------+--------------------------+
| 1 | Ahmed Moustafa | 21 | Intermediate | ahmed@university.edu |
| 2 | Osama Ali | 21 | Intermediate | osama.ali@university.edu |
| 3 | Mohamed Adel | 23 | Advanced | mohamed@university.edu |
| 4 | Kamal Mahmoud | 22 | Advanced | kamal@university.edu |
| 5 | Ayman Hassan | 21 | Advanced | ayman@university.edu |
| 6 | Adam Ibrahim | NULL | Beginner | adam@university.edu |
| 7 | Ismail Khaled | 23 | Advanced | ismail@university.edu |
+----+-----------------+------+--------------+--------------------------+
حذف بناءًا على شروط متعددة
لا أريد أن أطيل عليك هنا لأن لا شيء أخر يذكر عن الـ DELETE
لأن الـ WHERE أنت تعرف كيف تتعامل معه بالفعل
ويمكنك أن تتخيل أنك تستطيع استخدام كل شيء من شروط الـ WHERE التي تعلمتها في المقالات السابقة لكيف تقوم بحذف البيانات بناءًا على شروط متعددة
بالتالي تستطيع استخدام AND و OR و IN و BETWEEN و LIKE وغيرها من الشروط التي تعلمتها في المقالات السابقة
لأن أوامر الـ SQL متشابهه إلى حد كبير خصوصًا جزء الـ WHERE لأنه مشترك في كل الأوامر التي تتعامل مع البيانات مثل SELECT و UPDATE و DELETE
الفرق بين DELETE و TRUNCATE و DROP
نحن لدينا الآن ثلاثة أوامر رئيسية لحذف البيانات من الجداول في الـ SQL وهى DELETE و TRUNCATE و DROP
دعنا نفهم الفرق بينهم وكيفية استخدام كل واحد منهم
DELETE
هى كما شرحنا سابقًا تستخدم لحذف صفوف من جدول بناءً على شروط محددة
مثال:
DELETE FROM Students WHERE age < 18;
ولو أردنا حذف جميع الصفوف في الجدول لا نستخدم WHERE:
DELETE FROM Students;
أهم الأمور التي يجب أن تعرفها عن الـ DELETE:
- يحذف الصفوف واحدة تلو الأخرى بالتالي يعد بطيء مع الجداول الكبيرة
- يمكن استخدام
WHEREمعه وتحديد الصفوف التي تريد حذفها وهذه الميزة الأساسية له - يمكن التراجع عنه بـ
ROLLBACKإذا كنت تنفذ الأمر داخلTransactionوحدث خطأ ما في التنفيذ
وهناك مقالة مخصصة عن الـTransactionوكيفية استخدامها في الـSQL - لا يقوم بحذف الجدول بل يقوم بحذف البيانات فقط
- لا يقوم بإعادة تعيين الـ
AUTO_INCREMENT
بمعنى لو كان لديك جدولStudentsمع عمودidمن نوعAUTO_INCREMENT
ولديك10طلاب فبديهيًا عندما تضيف طالبًا جديدًا سيكونidالخاص به هو11
هنا عندما تقوم بحذف أي طالب أو حتى جميع الطلاب باستخدامDELETE
وقمت بإضافة طالب جديد، سيكونidالخاص به هو11أيضًا ولن يقوم بإعادة تعيينه إلى1
لذا يمكنك استخدام DELETE لحذف صفوف محددة بناءً على شروط معينة
TRUNCATE
الـ TRUNCATE هو أمر يستخدم لحذف جميع البيانات في الجدول دون استخدام شرط WHERE
وهو أسرع من DELETE لأنه لا يحذف الصفوف واحدة تلو الأخرى بل يقوم بحذف كل البيانات دفعة واحدة
ويعد من أخطر الأوامر في الـ SQL لأنه لا يمكن التراجع عنه وأيضًا لا نستخدم معه WHERE
TRUNCATE TABLE Students;
هكذا نقوم بحذف جميع البيانات في الجدول Students كأنك استخدمت DELETE بدون WHERE
أو لأكون أكثر دقة كأنك قمت بإنشاء الجدول من جديد
أهم الأمور التي يجب أن تعرفها عن الـ TRUNCATE:
- يحذف جميع الصفوف بعملية واحدة لذا يعد أسرع بكثير من
DELETE
لأنه لا يحذف الصفوف واحدة تلو الأخرى بل يقوم بحذف كل البيانات دفعة واحدة - لا يمكن استخدام
WHEREمعه - لا يمكن التراجع عنه حتى لو كنت تستخدم
Transaction(مع ملاحظات سنوضحها لاحقًا) - يقوم بإعادة تعيين الـ
AUTO_INCREMENTويجعله يبدأ من1
بمعنى لو كان لديك جدولStudentsمع عمودidمن نوعAUTO_INCREMENT
ولديك10طلاب، بعد تنفيذTRUNCATEوإضافة طالب جديد سيكونidالخاص به هو1وليس11
لذا استخدم TRUNCATE عندما تريد حذف جميع البيانات الموجودة في الجدول دون استخدام أي شرط
DROP
الـ DROP هو أمر يستخدم لحذف الجدول بالكامل وجميع البيانات الموجودة فيه
كأن الجدول لم يكن موجودًا من الأساس
وهذا يعد أخطر الأوامر في الـ SQL لأنه لا يمكن التراجع عنه
ولأنه يقوم بحذف الجدول بالكامل وليس فقط البيانات الموجودة فيه
DROP TABLE Students;
هكذا نقوم بحذف الجدول Students بالكامل
وهنا عليك استخدام الأمر CREATE لإنشاء الجدول من جديد إذا كنت تريد استخدامه مرة أخرى
أهم الأمور التي يجب أن تعرفها عن الـ DROP:
- يحذف الجدول بالكامل بما في ذلك جميع البيانات والهيكل
كأنك لم تقم بإنشاء الجدول من الأساس - لا يمكن استخدام
WHEREمعه لأنه لا يحذف صفوفًا بل يحذف الجدول بالكامل - لا يمكن التراجع عنه حتى لو كنت تستخدم
Transaction - يجب أن تكون حذرًا عند استخدامه لأنه سيؤدي إلى فقدان جميع البيانات الموجودة في الجدول ووظيفتك في الشركة أيضًا
نستخدم الـ DROP عندما نريد التخلص من جدول لم نعد بحاجة إليه أو عندما نريد إعادة إنشاء الجدول من جديد بشكل جديد بسبب تغييرات في التصميم أو الهيكل
وبالطبع يتم أخذ ألف حساب قبل استخدام أي أمر من هؤلاء الأوامر الثلاثة
Soft Delete vs Hard Delete
كما ذكرنا في بداية المقالة، أن معظم الشركات والمشاريع لا تستخدم أمر DELETE
لأن هذا النوع من الحذف يسمى Hard Delete وهو حذف نهائي لا يمكن التراجع عنه
بدلاً من ذلك، تستخدم الشركات شيئًا يدعى Soft Delete وهو عبارة عن وضع علامة على البيانات بأنها محذوفة دون حذفها فعليًا من قاعدة البيانات
فقط نتظاهر بأنها محذوفة عن طريق إضافة عمود جديد في الجدول يدعى deleted_at أو is_deleted أو status
والذي يحتوي على معلومات تدل على أن هذا الصف محذوف أم لا
وهذا يسمح لنا بـ استرجاع البيانات المحذوفة إذا احتجنا إليها مرة أخرى
قد تلاحظ أن معظم المواقع التي تقوم بحذف شيء ما تقول لك أن المنتج تم وضعه في سلة المهملات وسيتم حذفه نهائيًا بعد فترة معينة
وهذا هو مفهوم الـ Soft Delete
وهو يساعد على الحفاظ على البيانات في حالة الحاجة إليها لاحقًا
أو إن قام المستخدم بحذف شيء عن طريق الخطأ ويريد استرجاعه مرة أخرى
ما هو الـ Hard Delete ؟
الـ Hard Delete هو الحذف الحقيقي للبيانات من قاعدة البيانات باستخدام أمر DELETE
وهو حذف نهائي لا يمكن التراجع عنه في معظم الحالات
مثال على الـ Hard Delete هو ما كنا نقوم به عند استخدام أمر الـ DELETE:
DELETE FROM Students WHERE id = 1;
بعد تنفيذ هذا الأمر، سيتم حذف الطالب صاحب الـ id رقم 1 نهائيًا من قاعدة البيانات
ولن نستطيع استرجاعه مرة أخرى إلا إذا كان لدينا نسخة احتياطية من قاعدة البيانات
ما هو الـ Soft Delete ؟
الـ Soft Delete كما قلنا عبارة عن وضع علامة على البيانات بأنها محذوفة دون حذفها فعليًا من قاعدة البيانات
وهذا يتم عن طريق إضافة عمود جديد في الجدول يدعى deleted_at أو is_deleted أو status
والذي يحتوي على معلومات تدل على أن هذا الصف محذوف أم لا
ويساعد على الحفاظ على البيانات في حالة الحاجة إليها لاحقًا
أو إن قام المستخدم بحذف شيء عن طريق الخطأ ويريد استرجاعه مرة أخرى
مثال على تطبيق الـ Soft Delete:
أولاً، نحتاج إلى إضافة عمود جديد في جدول Students يدعى deleted_at:
ALTER TABLE Students
ADD COLUMN deleted_at TIMESTAMP NULL DEFAULT NULL;
هنا أضفنا عمودًا جديدًا يدعى deleted_at من نوع TIMESTAMP والذي سيحتوي على تاريخ ووقت الحذف
وجعلنا القيمة الافتراضية له NULL
وهذا سيخبرنا إذا كان قيمة العمود deleted_at هي NULL فهذا يعني أن الصف لم يتم حذفه
وإن كان العمود يحتوي على قيمة، فهذا يعني أن الصف تم حذفه
ولأننا نستخدم TIMESTAMP، سنعرف أيضًا متى تم حذف الصف
لنرى شكل الجدول الآن بعد إضافة العمود الجديد:
+----+-----------------+------+--------------+--------------------------+------------+
| id | name | age | level | email | deleted_at |
+----+-----------------+------+--------------+--------------------------+------------+
| 1 | Ahmed Moustafa | 21 | Intermediate | ahmed@university.edu | NULL |
| 2 | Osama Ali | 21 | Intermediate | osama.ali@university.edu | NULL |
| 3 | Mohamed Adel | 23 | Advanced | mohamed@university.edu | NULL |
| 4 | Kamal Mahmoud | 22 | Advanced | kamal@university.edu | NULL |
| 5 | Ayman Hassan | 21 | Advanced | ayman@university.edu | NULL |
| 6 | Adam Ibrahim | NULL | Beginner | adam@university.edu | NULL |
| 7 | Ismail Khaled | 23 | Advanced | ismail@university.edu | NULL |
+----+-----------------+------+--------------+--------------------------+------------+
الآن بدلاً من استخدام DELETE لحذف الطالب، نستخدم UPDATE لوضع علامة على أنه محذوف:
-- Soft Delete
UPDATE Students
SET deleted_at = NOW()
WHERE id = 1;
كما تلاحظ الـ Soft Delete لا يستخدم DELETE بل يستخدم UPDATE لتحديث العمود deleted_at
فكما تلاحظ هنا قمنا بتحديث العمود deleted_at للطالب صاحب الـ id رقم 1 ليصبح بتاريخ اليوم عن طريق دالة في الـ SQL تدعى NOW()
لنرى شكل الجدول الآن:
+----+-----------------+------+--------------+--------------------------+---------------------+
| id | name | age | level | email | deleted_at |
+----+-----------------+------+--------------+--------------------------+---------------------+
| 1 | Ahmed Moustafa | 21 | Intermediate | ahmed@university.edu | 2025-07-17 18:45:24 |
| 2 | Osama Ali | 21 | Intermediate | osama.ali@university.edu | NULL |
| 3 | Mohamed Adel | 23 | Advanced | mohamed@university.edu | NULL |
| 4 | Kamal Mahmoud | 22 | Advanced | kamal@university.edu | NULL |
| 5 | Ayman Hassan | 21 | Advanced | ayman@university.edu | NULL |
| 6 | Adam Ibrahim | NULL | Beginner | adam@university.edu | NULL |
| 7 | Ismail Khaled | 23 | Advanced | ismail@university.edu | NULL |
+----+-----------------+------+--------------+--------------------------+---------------------+
هنا بالنظر عرفنا أن الطالب Ahmed Moustafa تم حذفه لأنه يحتوي على قيمة في العمود deleted_at
ونعرف متى تم حذفه ولو أردنا استرجاعه، يمكننا ببساطة تحديث العمود deleted_at ليصبح NULL
لاحظ أنني هنا استخدمت فكرة الـ deleted_at لتحقيق الـ Soft Delete بدلًا من استخدام is_deleted أو status
لأنه من رأيي الشخصي الذي ليس له قيمة أرى أن استخدم deleted_at أفضل من استخدام is_deleted أو status
لأن deleted_at يعطيك تاريخ ووقت الحذف، مما يساعد في تتبع البيانات المحذوفة
أما is_deleted أو status قد لا يعطيك هذه المعلومة
وتخيل أنك تريد حذف العناصر التى مر على حذفها أكثر من 30 يومًا
هنا ستحتاج إلى معرفة تاريخ ووقت الحذف
كيف نتعامل مع البيانات المحذوفة بـ Soft Delete ؟
كما ذكرنا، عندما نستخدم Soft Delete، نقوم بتحديث العمود deleted_at بدلاً من حذف الصف فعليًا
لذا سيصبح لدينا صفوف في الجدول تحتوي على بيانات محذوفة وأخرى غير محذوفة
بالتالي عندما نريد عرض البيانات، نحتاج إلى تجاهل الصفوف التي تحتوي على قيمة في العمود deleted_at
أي نتجاهل الصفوف التي تم وضع علامة عليها بأنها محذوفة
بالتالي بدلاً من استخدام:
SELECT * FROM Students;
نستخدم:
SELECT * FROM Students
WHERE deleted_at IS NULL;
هكذا سنحصل على جميع الطلاب الذين لم يتم حذفهم فقط
ولو أردنا عرض الطلاب الذين تم حذفهم، نستخدم بكل بساطة نعكس الشرط:
SELECT * FROM Students
WHERE deleted_at IS NOT NULL;
استرجاع البيانات المحذوفة بـ Soft Delete
الآن لنفترض أن لدينا مستخدم قام بحذف بيانات الطالب Ahmed Moustafa بشكل غير مقصود
لذا نريد استرجاعه مرة أخرى بسرعة
هنا إذا أردنا استرجاع البيانات المحذوفة، يمكننا ببساطة تحديث العمود deleted_at ليصبح NULL:
UPDATE Students
SET deleted_at = NULL
WHERE id = 1;
هكذا نكون قد استرجعنا الطالب صاحب الـ id رقم 1 من الحذف
ويمكنك التأكد بنفسك
SELECT * FROM Students
WHERE id = 1;
هكذا ستجد أن الطالب Ahmed Moustafa عاد مرة أخرى إلى الجدول لأنه لم يعد يحتوي على قيمة في العمود deleted_at
+----+-----------------+------+--------------+--------------------------+------------+
| id | name | age | level | email | deleted_at |
+----+-----------------+------+--------------+--------------------------+------------+
| 1 | Ahmed Moustafa | 21 | Intermediate | ahmed@university.edu | NULL |
+----+-----------------+------+--------------+--------------------------+------------+
مميزات الـ Soft Delete
مميزات استخدام الـ Soft Delete كثيرة، منها:
- إمكانية استرجاع البيانات: أهم ميزة هي أنه يمكننا استرجاع البيانات المحذوفة إذا احتجنا إليها
- تجنب الأخطاء: لا يمكن فقدان البيانات بالخطأ لأنها لا تُحذف فعليًا
- التتبع: يمكننا معرفة متى تم حذف البيانات ومن قام بحذفها
والاحتفاظ بسجل كامل لجميع العمليات التي تمت على البيانات - استخدامها في التقارير: يمكننا استخدام البيانات المحذوفة في التقارير أو التحليلات لدراسة سلوك المستخدمين
أو معرفة المنتجات التي تم حذفها ولماذا تم حذفها
وتسمح لك باضافة ميزة في تطبيقك كسلة المهملات لتسمح للمستخدمين برؤية العناصر المحذوفة واسترجاعها إذا أرادوا ذلك
عيوب الـ Soft Delete
- استهلاك المساحة: البيانات المحذوفة تستمر في استهلاك مساحة في قاعدة البيانات لأنك لا تحذفها فعليًا
- التعقيد: يصبح الكود أكثر تعقيدًا لأننا نحتاج إلى إضافة شرط لتجنب البيانات المحذوفة في كل مرة تستخدم
SELECTأوUPDATE
ستلاحظ أنك ستحتاج دائمًا إلى إضافة شرطWHERE deleted_at IS NULLفي كل مرة لتجنب احضار أو تعديل البيانات المحذوفة - الأداء: مع زيادة حجم البيانات في الجدول، قد يؤثر ذلك على أداء الـ
queryالبسيطة
لأننا نحتاج إلى إضافة شرطWHERE deleted_at IS NULLفي كلqueryوهذا قد يؤدي إلى بطء في الأداء مع الجداول الكبيرة - التكرار: قد تحدث مشاكل مع البيانات المتكررة إذا لم نتعامل معها بشكل صحيح
على سبيل المثال لديك الـemailهوuniqueثم قام طالب بحذف حسابه فأنت قمت بعملSoft Delete
هنا عندما يحاول طالب آخر التسجيل بنفس البريد الإلكتروني، سيحدث تعارض لأن البريد الإلكتروني موجود بالفعل
حتى لأن هناك طالب محذوف بنفس البريد الإلكتروني
في هذه الحالة إذا كنت متأكد أنه نفس الشخص يمكنك أن تطلب منه التأكيد على استرجاع حسابه عن طريق رسالة ترسلها إلى بريده الإلكتروني
لتجنب مشاكل الـ Soft Delete، يتم اعطاء مهلة زمنية معينة للبيانات المحذوفة
فمثلًا عندما تقوم بحذف حسابك من موقع ما يعطيك مهلة شهر أو شهرين لاسترجاع حسابك
بعد هذه المهلة يتم حذف البيانات نهائيًا من قاعدة البيانات باستخدام Hard Delete
أو يتم نقل المعلومات الخاصة بك إلى أرشيف خاص بالبيانات المحذوفة من أجل تحليلها وبيعها دون إذنك وهذه الأمور التى نعرفها جميعًا
هل حقًا لا نستطيع استعادة البيانات المحذوفة كـ Hard Delete ؟
الإجابة على هذا السؤال تعتمد على نوع الـ DBMS الذي تستخدمه وما الأمر الذي استخدمته لحذف البيانات
نحن تعلمنا هنا ثلاثة أوامر رئيسية لحذف البيانات وهي DELETE و TRUNCATE و DROP
نفهم شيئًا مهمًا هنا قبل أن نقوم بعمل جدول ونقارن بين هذه الأوامر الثلاثة
عليك أن تعرف أن كل أمر تقوم بتنفيذه في الـ SQL يسجل في ملفات الـ log ومعها تفاصيل عن الأمر الذي تم تنفيذه وعن البيانات التي تأثرت ومتى... إلخ
وملفات الـ log تختلف خصائصها من نظام لآخر فكل DBMS له طريقة مختلفة في التعامل مع ملفات الـ log ويسميها بمصطلحات مختلفة:
- في الـ
MySQLتسمىbinary log - في الـ
PostgreSQLتسمىWALأيWrite Ahead Log - وفي الـ
SQL ServerتسمىTransaction Logوهي ملفات تنتهي بـ.ldf
وهذه الملفات تخزن كل العمليات التي تتم على قاعدة البيانات سواء كانت إضافة أو تعديل أو حذف
لنغوص قليلاً ونتعرف كيف تتعامل كل DBMS مع هذه الأوامر الثلاثة وهل يمكن استرجاع البيانات المحذوفة أم لا
معظم ما سنتحدث عنه في الفقرة التالية له علاقة بمفهوم الـ Durability في الـ ACID
وهو أحد مبادئ الـ ACID والذي استفضنا في شرحه في مقالة سابقة عن الـ Transaction وهي مقالة مبادئ الـ ACID في إدارة الـ Transactions
كيف تتعامل MySQL مع أوامر الحذف
كل عملية تتم داخل الـ MySQL يتم تسجيلها في ملفات تسمى binlog
ومن ضمن هذه العمليات أوامر الحذف مثل DELETE و TRUNCATE و DROP
أمر الـ DELETE في MySQL
مع استخدام الـ Transaction:
- يتم تسجيل الأمر والبيانات المحذوفة بالكامل في ملفات الـ
binlog - يمكن استخدام
ROLLBACKلاستعادة البيانات المحذوفة بنجاح لأن البيانات مسجلة في ملفات الـbinlog
بدون استخدام الـ Transaction:
- يتم تسجيل البيانات المحذوفة في
binlogأيضًا - يمكن استعادة البيانات باستخدام أدوات تقوم بتحليل ملفات الـ
binlogلتستطيع فك تشفيرها ومعرفة البيانات المحذوفة وإعادتها
ملحوظة: ملفات الـbinlogقد تُحذف تلقائيًا بعد فترة محددة حسب إعدادات الـMySQLأو قد يتم حذفها يدويًا
لذا يجب أن تكون حذرًا لأن ملفات الـbinlogليست مضمونة وقد لا تكون متاحة دائمًا للاستعادة
أمر الـ TRUNCATE في MySQL
سواء كنت تستخدم Transaction أو لا:
- يتم تسجيل الأمر نفسه في ملفات الـ
binlogلكن بدون تفاصيل عن البيانات المحذوفة - لا يمكن استخدام
ROLLBACKداخلTransactionلاستعادة البيانات لأنTRUNCATEلا يحتفظ بتفاصيل الصفوف المحذوفة لأنه يحذفها دفعة واحدة كأنه يقول لك "تم حذف جميع البيانات في الجدول" بدون أن يعطيك تفاصيل عن الصفوف المحذوفة - لا يمكن استعادة البيانات المحذوفة بعد أن تم عمل
TRUNCATEبنجاح لأنTRUNCATEلا يسجل تفاصيل الصفوف المحذوفة في ملفات الـbinlog
أمر الـ DROP في MySQL
نفس سلوك أمر الـ TRUNCATE تمامًا:
كل شيء قلناه عن TRUNCATE ينطبق على DROP أيضًا
سواء كنت تستخدم Transaction أو لا:
- يتم تسجيل الأمر في ملف الـ
binlogلكن بدون تفاصيل عن البيانات المحذوفة - لا يمكن استخدام
ROLLBACKلاستعادة الجدول المحذوف - لا يمكنك استعادة الجدول أو بياناته بعد تنفيذ
DROPبأي شكل من الأشكال - يضمن لك الفصل السريع من الشركة التي تعمل بها
ستلاحظ أن كلًا من TRUNCATE و DROP لا يسجلان البيانات التي تم حذفها في ملفات binlog
ولا يتأثران بأي عمليات ROLLBACK داخل Transaction
لذا يجب أن تكون حذرًا جدًا عند استخدام TRUNCATE و DROP لأنه لا يمكنك استرجاع البيانات المحذوفة بأي شكل من الأشكال
كيف تتعامل PostgreSQL مع أوامر الحذف
في الـ PostgreSQL الوضع مختلف قليلاً عن الـ MySQL ولكن المبدأ العام متشابه
كل عملية تتم داخل الـ PostgreSQL يتم تسجيلها في ملفات تسمى WAL وهي اختصار لـ Write Ahead Log
أمر الـ DELETE في PostgreSQL
مع استخدام الـ Transaction:
- يتم تسجيل كامل تفاصيل البيانات المحذوفة في ملف الـ
WAL - يمكنك استخدام الـ
ROLLBACKلاستعادة البيانات المحذوفة لأن البيانات مسجلة في ملف الـWAL
بدون استخدام الـ Transaction:
- يتم الاحتفاظ بتفاصيل البيانات المحذوفة في ملف الـ
WAL - يمكنك استعادة البيانات المحفوظة باستخدام أدوات تتعامل مع ملف الـ
WAL
ملحوظة: يتم الاحتفاظ بملفات الـWALلفترة طويلة لكن قد يتم حذفها تلقائيًا لأسباب معينة يتبعها الـPostgreSQLأو يتم حذفها بشكل يدوي بسبب زيادة حجم الملف
أمر الـ TRUNCATE في PostgreSQL
مع استخدام الـ Transaction:
- يتم تسجيل الأمر في ملف الـ
WALلكن بدون تفاصيل عن الصفوف المحذوفة - يمكن استخدام
ROLLBACKبنجاح لاستعادة البيانات في حالة حصول مشكلة في الـTransactionوهذه ميزة مهمة جدًا في الـPostgreSQLيتفوق بها على الـMySQL - الـ
PostgreSQLيؤجل التنفيذ الفعلي لـTRUNCATEحتى تأكيد الـTransactionعن طريقCOMMIT - لا يمكن استعادة البيانات المحذوفة بعد تنفيذ
TRUNCATEبنجاح لأنTRUNCATEلا يسجل تفاصيل الصفوف المحذوفة في ملف الـWAL
بدون استخدام الـ Transaction:
- لا يمكن استعادة البيانات لأن تفاصيلها لا تسجل في ملف الـ
WAL - الأمور هنا مشابهة لما يحدث في الـ
MySQLفي هذه الحالة
أمر الـ DROP في PostgreSQL
سواء كنت تستخدم Transaction أو لا:
- لا يتم تسجيل البيانات المحذوفة في ملف الـ
WAL - لا يمكن استخدام
ROLLBACKلاستعادة الجدول المحذوف - لا يمكنك استعادة الجدول أو بياناته بعد تنفيذ
DROPبنجاح - كما ذكرنا فإنه يضمن لك الفصل السريع من الشركة التي تعمل بها
لاحظ أن الفرق الرئيسي بين MySQL و PostgreSQL في التعامل مع أوامر الحذف هو أن PostgreSQL يسمح لك باستخدام ROLLBACK مع TRUNCATE داخل Transaction، بينما MySQL لا يسمح بذلك، لذا يجب أن تكون حذرًا عند استخدامها
ولاحظ أن أمر DROP لا يتأثر أيضًا بأي عمليات ROLLBACK داخل Transaction لأنه يعد من أوامر الـ DDL التي تقوم بعمل commit تلقائي لنفسها سواء كانت داخل Transaction أم لا
كيف تتعامل SQL Server مع أوامر الحذف
الـ SQL Server له نظام مختلف تمامًا عن MySQL و PostgreSQL في التعامل مع الأوامر بشكل عام
كل عملية تتم داخل الـ SQL Server يتم تسجيلها في ملفات تسمى Transaction Log وهي ملفات تنتهي بـ .ldf وهي اختصار لـ Log Data File
أمر الـ DELETE في SQL Server
مع استخدام الـ Transaction:
- يتم تسجيل كامل تفاصيل البيانات المحذوفة في ملفات الـ
ldf - يمكنك استخدام الـ
ROLLBACKلاستعادة البيانات المحذوفة لأن البيانات مسجلة في ملفات الـldf
بدون استخدام الـ Transaction:
- يتم الاحتفاظ بتفاصيل البيانات المحذوفة في ملفات الـ
ldf - يمكنك استعادة البيانات المحفوظة باستخدام أدوات تتعامل مع ملفات الـ
ldf
ستلاحظ أن أمر الـ DELETE في كل من MySQL و PostgreSQL و SQL Server
تستطيع استعادة البيانات المحذوفة سواء كنت تستخدم Transaction أو لا
لأن كل هذه الأنظمة تحتفظ بتفاصيل البيانات المحذوفة في ملفات الـ log الخاصة بها
أمر الـ TRUNCATE في SQL Server
سترى هنا أنه يتصرف بشكل مشابه لـ PostgreSQL
مع استخدام الـ Transaction:
- يتم تسجيل الأمر في ملفات الـ
ldfلكن بدون تفاصيل عن الصفوف المحذوفة - يمكنك استخدام
ROLLBACKلاستعادة البيانات المحذوفة في حالة حدوث مشكلة في الـTransaction - مثلما حدث في
PostgreSQLفهنا الـSQL Serverيؤجل التنفيذ الفعلي لـTRUNCATEحتى تأكيد الـTransactionعن طريقCOMMIT - لا يمكن استعادة البيانات المحذوفة بعد تنفيذ
TRUNCATEبنجاح لأنTRUNCATEلا يسجل تفاصيل الصفوف المحذوفة في ملفات الـldf
بدون استخدام الـ Transaction:
- لا يتم الاحتفاظ بتفاصيل الصفوف المحذوفة في ملفات الـ
ldf - لا يمكن استعادة البيانات المحذوفة بعد تنفيذ الـ
TRUNCATEبنجاح لأنها لا تسجل تفاصيل الصفوف المحذوفة في ملفات الـldf - الأمور هنا مشابهة لما يحدث في
MySQLوPostgreSQLفي هذه الحالة
أمر الـ DROP في SQL Server
نفس سلوك PostgreSQL
سواء كنت تستخدم Transaction أو لا:
- لا يتم تسجيل البيانات المحذوفة في ملفات الـ
ldf - لا يمكن استخدام
ROLLBACKلاستعادة الجدول المحذوف - لا يمكنك استعادة الجدول أو بياناته بعد تنفيذ
DROPبنجاح - وكالعادة يضمن لك الفصل السريع من الشركة التي تعمل بها
ستلاحظ أن SQL Server يتعامل مع أوامر الحذف بشكل مشابه لـ PostgreSQL مع اختلاف المصطلحات فقط
فكلاهما يسمحان باستخدام ROLLBACK مع TRUNCATE داخل Transaction
بينما MySQL لا يسمح بذلك
وستلاحظ أن أمر الـ DROP في كل من MySQL و PostgreSQL و SQL Server
لا يتأثر بأي عمليات ROLLBACK داخل Transaction
لأنه يعد من أوامر الـ DDL التي تقوم بعمل commit تلقائي لنفسها سواء كانت داخل Transaction أم لا
ولا يمكن استعادة البيانات المحذوفة بأي شكل من الأشكال بعد تنفيذ TRUNCATE أو DROP
لأنهما لا يسجلان تفاصيل الصفوف المحذوفة في ملفات الـ log الخاصة بكل نظام
ملحوظة: في الـSQL Serverملفات الـldfهي الخاصة بتسجيل العمليات التي تتم على قاعدة البيانات
وبعد أن يتم عملcommitيتم نقل البيانات إلى ملفات الـmdfوهي ملفات البيانات الرئيسية التي تمثل الـDatabaseأو الـSchemaالتي تحتوي على الجداول والبيانات
ملحوظة: هناك مميزات وإضافات يتم إضافتها إلى كلDBMSلتساعدك على استعادة البيانات المحذوفة وتجنب الأخطاء
ستجد أنه في كل فترة يتم تطويره وإضافة مميزات جديدة تساعد على استعادة البيانات المحذوفة أو التعامل مع الأخطاء بشكل أفضل
لذا يجب عليك متابعة التحديثات الخاصة بالـDBMSالذي تستخدمه ومعرفة المميزات الجديدة التي يتم إضافتها
جدول مقارنة أوامر الحذف في MySQL و PostgreSQL و SQL Server
| العملية | MySQL | PostgreSQL | SQL Server |
|---|---|---|---|
| DELETE داخل Transaction | يتم تسجيل البيانات في ملف binlogيمكن عمل ROLLBACK |
يتم تسجيل البيانات في ملف WALيمكن عمل ROLLBACK |
يتم تسجيل البيانات في ملف ldfيمكن عمل ROLLBACK |
| DELETE خارج Transaction | يتم تسجيل البيانات في ملف binlogيمكن استعادة البيانات بأدوات خارجية |
يتم تسجيل البيانات في ملف WALيمكن استعادة البيانات بأدوات خارجية |
يتم تسجيل البيانات في ملف ldfيمكن استعادة البيانات بأدوات خارجية |
| TRUNCATE داخل Transaction | لا يتم تسجيل البيانات لا يمكن عمل ROLLBACK حتى ولو حدوث خطأ للـ Transaction |
لا يتم تسجيل البيانات يمكن عمل ROLLBACK في في حالة حدوث خطأ للـ Transaction |
لا يتم تسجيل البيانات يمكن عمل ROLLBACK في في حالة حدوث خطأ للـ Transaction |
| TRUNCATE خارج Transaction | لا يتم تسجيل البيانات لا يمكن استعادة البيانات |
لا يتم تسجيل البيانات لا يمكن استعادة البيانات |
لا يتم تسجيل البيانات لا يمكن استعادة البيانات |
| DROP داخل Transaction | لا يتم تسجيل تفاصيل الجدول لا يمكن عمل ROLLBACK حتى ولو حدوث خطأ للـ Transaction |
لا يتم تسجيل تفاصيل الجدول لا يمكن عمل ROLLBACK حتى ولو حدوث خطأ للـ Transaction |
لا يتم تسجيل تفاصيل الجدول لا يمكن عمل ROLLBACK حتى ولو حدوث خطأ للـ Transaction |
| DROP خارج Transaction | لا يتم تسجيل تفاصيل الجدول لا يمكن استعادة البيانات |
لا يتم تسجيل تفاصيل الجدول لا يمكن استعادة البيانات |
لا يتم تسجيل تفاصيل الجدول لا يمكن استعادة البيانات |
الخلاصة
في هذه المقالة تعلمنا كيفية استخدام أمر DELETE لحذف البيانات من الجداول في الـ SQL
وأهم النقاط التي يجب أن تتذكرها:
- أمر
DELETEخطير جدًا ويجب استخدامه بحذر شديد - استخدم
WHEREدائمًا لتحديد الصفوف التي تريد حذفها - استخدم
SELECTقبلDELETEللتأكد من البيانات التي ستحذف - الفرق بين
DELETEوTRUNCATEوDROP:DELETE: لحذف صفوف محددة مع إمكانية استخدامWHERETRUNCATE: لحذف جميع الصفوف بسرعة دفعة واحدةDROP: لحذف الجدول بالكامل
- الفرق بين الـ
Soft DeleteوHard DeleteSoft Delete: وضع علامة على البيانات بأنها محذوفة دون حذفها فعليًاHard Delete: حذف البيانات نهائيًا باستخدامDELETEأوTRUNCATE
هكذا نكون تعلمنا الأوامر الأساسية الخاصة بالـ DML في الـ SQL وهى CREATE و INSERT و SELECT و UPDATE و DELETE
في المقالة التالية، سنتعلم المزيد عن أوامر الـ SQL ونعطي أمثلة ومسائل عن الـ SQL
ونتعرف على بعض الدوال الخاصة بالـ SQL وكيفية استخدامها