SQL: تحديث وحذف البيانات
تحديث البيانات باستخدام UPDATE
عبارة UPDATE تعدل السجلات الموجودة في جدول. كن حذراً جداً مع UPDATE - بدون شرط WHERE المناسب، ستقوم بتحديث جميع الصفوف!
الصيغة الأساسية
UPDATE table_name SET column1 = value1, column2 = value2, ... WHERE condition;
تحذير حاسم
قم دائماً بتضمين شرط WHERE إلا إذا كنت تريد عمداً تحديث جميع الصفوف. بدون WHERE، سيتم تحديث كل صف في الجدول!
-- خطير: يحدث جميع المنتجات! UPDATE products SET price = 0; -- آمن: يحدث منتج واحد محدد فقط UPDATE products SET price = 99.99 WHERE id = 5;
مثال: تحديث عمود واحد
-- تحديث البريد الإلكتروني للمستخدم UPDATE users SET email = 'newemail@example.com' WHERE id = 10;
مثال: تحديث أعمدة متعددة
-- تحديث سعر ومخزون المنتج UPDATE products SET price = 149.99, stock = 25 WHERE id = 3;
مثال: التحديث بناءً على شرط
-- إعطاء خصم 10% لجميع الإلكترونيات UPDATE products SET price = price * 0.9 WHERE category = 'Electronics'; -- وضع علامة على جميع المنتجات غير المتوفرة على أنها غير نشطة UPDATE products SET is_active = 0 WHERE stock = 0;
التحديث مع الحسابات
-- زيادة جميع الأسعار بنسبة 5% UPDATE products SET price = price * 1.05 WHERE category = 'Electronics'; -- إضافة 10 وحدات إلى المخزون UPDATE products SET stock = stock + 10 WHERE id = 15; -- زيادة عدد المشاهدات UPDATE posts SET views = views + 1 WHERE id = 42;
تحديث صفوف متعددة
-- تحديث جميع المنتجات في فئات محددة
UPDATE products
SET is_active = 1
WHERE category IN ('Electronics', 'Books', 'Furniture');
-- وضع علامة على الطلبات القديمة على أنها مؤرشفة
UPDATE orders
SET status = 'archived'
WHERE created_at < DATE_SUB(NOW(), INTERVAL 1 YEAR);
التحديث مع عبارة CASE
تطبيق تحديثات مختلفة بناءً على الشروط:
-- تطبيق خصومات مختلفة بناءً على نطاق السعر
UPDATE products
SET price = CASE
WHEN price > 500 THEN price * 0.80 -- خصم 20% للعناصر الباهظة
WHEN price > 100 THEN price * 0.90 -- خصم 10% للمتوسطة
ELSE price * 0.95 -- خصم 5% للأرخص
END
WHERE category = 'Electronics';
التحديث مع LIMIT
-- تحديث أول 10 صفوف مطابقة فقط UPDATE products SET is_featured = 1 WHERE category = 'Electronics' ORDER BY price DESC LIMIT 10;
فحص التحديثات قبل التنفيذ
أفضل ممارسة: اختبر باستخدام SELECT أولاً
قبل تشغيل UPDATE، قم بتشغيل SELECT بنفس شرط WHERE لرؤية الصفوف التي ستتأثر:
-- 1. أولاً، تحقق من الصفوف التي ستتأثر SELECT * FROM products WHERE category = 'Electronics' AND price < 50; -- 2. إذا كانت النتائج صحيحة، قم بتشغيل التحديث UPDATE products SET is_active = 0 WHERE category = 'Electronics' AND price < 50; -- 3. تحقق من التحديث SELECT * FROM products WHERE category = 'Electronics' AND price < 50;
حذف البيانات باستخدام DELETE
عبارة DELETE تزيل الصفوف من جدول. مثل UPDATE، خطير بدون شرط WHERE!
الصيغة الأساسية
DELETE FROM table_name WHERE condition;
يتطلب حذر شديد!
لا تنسَ أبداً شرط WHERE إلا إذا كنت تريد حذف جميع الصفوف!
-- كارثي: يحذف جميع المستخدمين! DELETE FROM users; -- آمن: يحذف مستخدم واحد محدد DELETE FROM users WHERE id = 10;
مثال: حذف صف واحد
-- حذف منتج محدد DELETE FROM products WHERE id = 5; -- حذف مستخدم محدد DELETE FROM users WHERE username = 'spam_account';
مثال: حذف صفوف متعددة
-- حذف جميع المنتجات غير النشطة DELETE FROM products WHERE is_active = 0; -- حذف الطلبات القديمة DELETE FROM orders WHERE created_at < DATE_SUB(NOW(), INTERVAL 2 YEAR); -- حذف المستخدمين الذين لم يسجلوا الدخول أبداً DELETE FROM users WHERE last_login IS NULL AND created_at < DATE_SUB(NOW(), INTERVAL 6 MONTH);
الحذف مع شروط متعددة
-- حذف الطلبات الملغاة الأقدم من 90 يوماً DELETE FROM orders WHERE status = 'cancelled' AND created_at < DATE_SUB(NOW(), INTERVAL 90 DAY); -- حذف التعليقات غير المرغوب فيها DELETE FROM comments WHERE (content LIKE '%viagra%' OR content LIKE '%casino%') AND created_at > DATE_SUB(NOW(), INTERVAL 7 DAY);
الحذف مع LIMIT
-- حذف أقدم 100 إدخال سجل DELETE FROM logs ORDER BY created_at ASC LIMIT 100;
اختبار الحذف بأمان
اختبر دائماً باستخدام SELECT أولاً
-- 1. معاينة ما سيتم حذفه SELECT * FROM products WHERE is_active = 0; -- 2. تحقق من العدد SELECT COUNT(*) FROM products WHERE is_active = 0; -- 3. إذا كان صحيحاً، تابع بالحذف DELETE FROM products WHERE is_active = 0; -- 4. تحقق من الحذف SELECT COUNT(*) FROM products WHERE is_active = 0; -- يجب أن يُرجع 0
الحذف الناعم مقابل الحذف الصلب
الحذف الصلب (دائم)
يزيل الصفوف فعلياً من قاعدة البيانات. البيانات ضائعة للأبد.
DELETE FROM users WHERE id = 10;
الحذف الناعم (موصى به للبيانات المهمة)
وضع علامة على الصفوف على أنها محذوفة بدلاً من إزالتها فعلياً. هذا يسمح بالاستعادة ويحافظ على سلامة الإشارات.
-- إضافة عمود deleted_at إلى جدولك ALTER TABLE users ADD COLUMN deleted_at TIMESTAMP NULL; -- "حذف" عن طريق تعيين الطابع الزمني UPDATE users SET deleted_at = NOW() WHERE id = 10; -- استبعاد السجلات "المحذوفة" في الاستعلامات SELECT * FROM users WHERE deleted_at IS NULL; -- استعادة سجل محذوف بشكل ناعم UPDATE users SET deleted_at = NULL WHERE id = 10;
فوائد الحذف الناعم
- قابل للاستعادة: يمكن استعادة البيانات المحذوفة عن طريق الخطأ
- مسار التدقيق: الاحتفاظ بتاريخ من حذف ماذا ومتى
- سلامة الإشارات: علاقات المفاتيح الخارجية تبقى سليمة
- التحليلات: يمكن تحليل أنماط البيانات المحذوفة
استخدم الحذف الناعم لـ: حسابات المستخدمين، الطلبات، المنشورات، السجلات التجارية المهمة
استخدم الحذف الصلب لـ: السجلات، البيانات المؤقتة، الرسائل غير المرغوب فيها، بيانات الجلسة القديمة
TRUNCATE مقابل DELETE
DELETE
-- يحذف الصفوف واحدة تلو الأخرى -- يمكن استخدام شرط WHERE -- يتم تنفيذ المحفزات -- أبطأ للجداول الكبيرة -- يمكن التراجع (في المعاملات) DELETE FROM logs WHERE created_at < '2023-01-01';
TRUNCATE
-- يزيل جميع الصفوف دفعة واحدة -- لا يُسمح بشرط WHERE -- أسرع بكثير -- يعيد تعيين عداد AUTO_INCREMENT -- لا يمكن التراجع TRUNCATE TABLE logs;
تحذير TRUNCATE: لا يمكن التراجع عن TRUNCATE ويحذف جميع البيانات. استخدمه فقط عندما تكون متأكداً تماماً!
الحذف المتتالي
عندما تقوم بإعداد المفاتيح الخارجية باستخدام ON DELETE CASCADE، فإن حذف صف أصلي يحذف تلقائياً الصفوف الفرعية المرتبطة.
-- إعداد الجدول مع CASCADE
CREATE TABLE orders (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
CREATE TABLE order_items (
id INT PRIMARY KEY AUTO_INCREMENT,
order_id INT NOT NULL,
FOREIGN KEY (order_id) REFERENCES orders(id) ON DELETE CASCADE
);
-- حذف مستخدم يحذف تلقائياً طلباته وعناصر طلباته
DELETE FROM users WHERE id = 10;
-- هذا يحذف أيضاً:
-- - جميع طلبات المستخدم 10
-- - جميع order_items لتلك الطلبات
خيارات المفتاح الخارجي الأخرى
- ON DELETE CASCADE: حذف الصفوف الفرعية تلقائياً
- ON DELETE SET NULL: تعيين المفتاح الخارجي إلى NULL (يجب أن يسمح العمود بـ NULL)
- ON DELETE RESTRICT: منع الحذف إذا كانت الصفوف الفرعية موجودة (افتراضي)
- ON DELETE NO ACTION: نفس RESTRICT
الصفوف المتأثرة
بعد UPDATE أو DELETE، تحقق من عدد الصفوف المتأثرة:
-- في MySQL CLI
UPDATE products SET price = 99.99 WHERE id = 5;
-- يظهر: Query OK, 1 row affected
-- في PHP (mysqli)
$result = $mysqli->query("UPDATE products SET price = 99.99 WHERE id = 5");
$affected = $mysqli->affected_rows;
echo "Updated $affected rows";
-- في PHP (PDO)
$stmt = $pdo->prepare("UPDATE products SET price = ? WHERE id = ?");
$stmt->execute([99.99, 5]);
$affected = $stmt->rowCount();
echo "Updated $affected rows";
أمان المعاملات
للتحديثات/الحذف الحاسمة، استخدم المعاملات لضمان اتساق البيانات:
-- بدء المعاملة START TRANSACTION; -- تنفيذ التحديثات UPDATE accounts SET balance = balance - 100 WHERE id = 1; UPDATE accounts SET balance = balance + 100 WHERE id = 2; -- إذا كان كل شيء يبدو جيداً، قم بالالتزام COMMIT; -- إذا حدث خطأ، تراجع ROLLBACK;
متى تستخدم المعاملات:
- تحويل الأموال بين الحسابات
- معالجة الطلبات (المخزون، الدفع، سجل الطلب)
- حذف السجلات المرتبطة عبر جداول متعددة
- أي عملية حيث الإنجاز الجزئي سيكون إشكالياً
أمثلة عملية
مثال 1: تحديث ملف تعريف المستخدم
-- تحديث معلومات ملف تعريف المستخدم
UPDATE users
SET
full_name = 'John Smith',
phone = '+1-555-0123',
address = '123 Main St',
updated_at = NOW()
WHERE id = 25;
مثال 2: إدارة حالة الطلب
-- وضع علامة على الطلب على أنه تم شحنه
UPDATE orders
SET
status = 'shipped',
shipped_at = NOW(),
tracking_number = 'TRACK12345'
WHERE id = 100;
-- إلغاء الطلبات المعلقة الأقدم من 30 يوماً
UPDATE orders
SET status = 'cancelled'
WHERE status = 'pending'
AND created_at < DATE_SUB(NOW(), INTERVAL 30 DAY);
مثال 3: إدارة المخزون
-- تقليل المخزون بعد الشراء UPDATE products SET stock = stock - 2 WHERE id = 15 AND stock >= 2; -- إعادة تخزين المنتجات UPDATE products SET stock = stock + 50, is_active = 1 WHERE id IN (10, 15, 20, 25);
مثال 4: تنظيف البيانات
-- حذف الحسابات غير المتحقق منها الأقدم من 7 أيام DELETE FROM users WHERE email_verified = 0 AND created_at < DATE_SUB(NOW(), INTERVAL 7 DAY); -- حذف بيانات الجلسة القديمة DELETE FROM sessions WHERE last_activity < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 2 HOUR)); -- أرشفة وحذف السجلات القديمة INSERT INTO archived_logs SELECT * FROM logs WHERE created_at < DATE_SUB(NOW(), INTERVAL 1 YEAR); DELETE FROM logs WHERE created_at < DATE_SUB(NOW(), INTERVAL 1 YEAR);
تمرين: عمليات إدارة البيانات
اكتب عبارات SQL للسيناريوهات التالية:
- تحديث المنتج #5 ليكون له سعر 79.99 دولار ومخزون 50
- إعطاء خصم 15% لجميع المنتجات في فئة "الكتب"
- وضع علامة على جميع الطلبات بحالة "تم التسليم" من 2023 على أنها "مكتملة"
- حذف جميع التعليقات التي تحتوي على كلمة "spam"
- حذف ناعم (تعيين deleted_at) للمستخدم بالبريد الإلكتروني "test@example.com"
- تحديث عدد المشاهدات لمنشور المدونة #42 عن طريق زيادته بمقدار 1
- حذف جميع المنتجات التي كانت غير نشطة لأكثر من سنة واحدة
- تحديث جميع المستخدمين الذين سجلوا قبل 2020 ليكون لديهم علامة "legacy_user" معينة على true
تذكر: اكتب استعلامات SELECT أولاً لمعاينة الصفوف المتأثرة!
ملخص أفضل الممارسات
قائمة التحقق من سلامة UPDATE/DELETE
- استخدم دائماً WHERE: إلا إذا كنت تريد عمداً التأثير على جميع الصفوف
- اختبر باستخدام SELECT أولاً: معاينة الصفوف التي ستتأثر
- احتفظ بنسخة احتياطية قبل العمليات المجمعة: أنشئ نسخة احتياطية لقاعدة البيانات للتحديثات/الحذف الكبيرة
- استخدم LIMIT: اختبر على صفوف قليلة أولاً باستخدام LIMIT
- تحقق من الصفوف المتأثرة: تحقق من العدد المتوقع من الصفوف المتغيرة
- استخدم المعاملات: للعمليات متعددة الخطوات الحاسمة
- فكر في الحذف الناعم: للبيانات المهمة التي قد تحتاج إلى استعادة
- أضف الطوابع الزمنية: تتبع متى تم تحديث السجلات (عمود updated_at)
- سجل التغييرات الحاسمة: احتفظ بمسار تدقيق للتعديلات المهمة
- استخدم قيود المفاتيح الخارجية: حافظ على سلامة الإشارات
ما التالي؟
في الدرس التالي، ستتعلم تقنيات الاستعلام المتقدمة بما في ذلك GROUP BY و HAVING والاستعلامات الفرعية ودوال التجميع لإجراء تحليل بيانات معقد.