انتقال للمقال

حذف البيانات باستخدام DELETE في الـ SQL

السلام عليكم ورحمة الله وبركاته

وقت القراءة: ≈ 20 دقيقة (بمعدل فنجان واحد من القهوة 😊)

المقدمة

لقد تعلمنا في المقالات السابقة الأوامر الأساسية للتعامل مع قواعد البيانات مثل 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: هذا يعني أننا نريد حذف بيانات من جدول Students
  • WHERE 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

  1. استهلاك المساحة: البيانات المحذوفة تستمر في استهلاك مساحة في قاعدة البيانات لأنك لا تحذفها فعليًا
  2. التعقيد: يصبح الكود أكثر تعقيدًا لأننا نحتاج إلى إضافة شرط لتجنب البيانات المحذوفة في كل مرة تستخدم SELECT أو UPDATE
    ستلاحظ أنك ستحتاج دائمًا إلى إضافة شرط WHERE deleted_at IS NULL في كل مرة لتجنب احضار أو تعديل البيانات المحذوفة
  3. الأداء: مع زيادة حجم البيانات في الجدول، قد يؤثر ذلك على أداء الـ query البسيطة
    لأننا نحتاج إلى إضافة شرط WHERE deleted_at IS NULL في كل query وهذا قد يؤدي إلى بطء في الأداء مع الجداول الكبيرة
  4. التكرار: قد تحدث مشاكل مع البيانات المتكررة إذا لم نتعامل معها بشكل صحيح
    على سبيل المثال لديك الـ 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
وأهم النقاط التي يجب أن تتذكرها:

  1. أمر DELETE خطير جدًا ويجب استخدامه بحذر شديد
  2. استخدم WHERE دائمًا لتحديد الصفوف التي تريد حذفها
  3. استخدم SELECT قبل DELETE للتأكد من البيانات التي ستحذف
  4. الفرق بين DELETE و TRUNCATE و DROP:
    • DELETE: لحذف صفوف محددة مع إمكانية استخدام WHERE
    • TRUNCATE: لحذف جميع الصفوف بسرعة دفعة واحدة
    • DROP: لحذف الجدول بالكامل
  5. الفرق بين الـ Soft Delete و Hard Delete
    • Soft Delete: وضع علامة على البيانات بأنها محذوفة دون حذفها فعليًا
    • Hard Delete: حذف البيانات نهائيًا باستخدام DELETE أو TRUNCATE

هكذا نكون تعلمنا الأوامر الأساسية الخاصة بالـ DML في الـ SQL وهى CREATE و INSERT و SELECT و UPDATE و DELETE
في المقالة التالية، سنتعلم المزيد عن أوامر الـ SQL ونعطي أمثلة ومسائل عن الـ SQL
ونتعرف على بعض الدوال الخاصة بالـ SQL وكيفية استخدامها