التعامل مع القيم الفارغة NULL
في عالم قواعد البيانات، القيمة NULL هي مفهوم فريد ومهم جداً يختلف تماماً عن القيم العادية. NULL لا تعني صفراً، ولا تعني نصاً فارغاً، بل تعني "غياب القيمة" أو "قيمة غير معروفة". في هذا الدرس الشامل من سلسلة تعلم لغة SQL باللغة العربية، سنتعلم كيفية التعامل مع NULL بشكل صحيح، الفخاخ الشائعة التي يقع فيها المبتدئون، والدوال المتخصصة للتعامل مع القيم الفارغة.
1. ما هو NULL في SQL؟
NULL هو قيمة خاصة في SQL تشير إلى "عدم وجود قيمة" أو "قيمة غير معروفة". NULL ليس صفراً، وليس نصاً فارغاً، وليس مسافة. إنه حالة خاصة تماماً.
أمثلة واقعية على NULL
- رقم الهاتف الثاني: إذا كان لديك عميل ليس لديه رقم هاتف ثانٍ، القيمة تكون NULL (وليس صفراً أو فارغاً)
- تاريخ الانتهاء: موظف لا يزال يعمل، تاريخ انتهاء عمله NULL
- الخصم: منتج بدون خصم، قيمة الخصم NULL (وليس 0%)
- البريد الإلكتروني: عميل لم يقدم بريده الإلكتروني، القيمة NULL
مثال: جدول يحتوي على NULL
+----+----------+--------+------------+------------+
| id | name | salary | phone2 | end_date |
+----+----------+--------+------------+------------+
| 1 | أحمد | 5000 | 0501234567 | NULL |
| 2 | فاطمة | 6000 | NULL | NULL |
| 3 | محمد | 5500 | 0509876543 | 2024-12-31 |
| 4 | سارة | 7000 | NULL | NULL |
+----+----------+--------+------------+------------+
-- أحمد: لديه رقم هاتف ثانٍ، لا يزال يعمل (end_date = NULL)
-- فاطمة: لا يوجد رقم هاتف ثانٍ (NULL)، لا تزال تعمل
-- محمد: لديه رقم هاتف ثانٍ، سينتهي عقده في 2024-12-31
-- سارة: لا يوجد رقم هاتف ثانٍ، لا تزال تعمل
2. الخطأ الشائع: استخدام = مع NULL
أكبر خطأ يقع فيه المبتدئون هو محاولة مقارنة NULL باستخدام = أو !=. هذا لا يعمل أبداً!
-- ❌ خطأ: هذا لن يعمل!
SELECT * FROM employees
WHERE phone2 = NULL;
-- النتيجة: 0 rows (لن يجلب أي شيء!)
-- ❌ خطأ: هذا أيضاً لن يعمل!
SELECT * FROM employees
WHERE phone2 != NULL;
NULL = NULL تعطي نتيجة غير معروفة (ليست TRUE ولا FALSE).
الطريقة الصحيحة: IS NULL و IS NOT NULL
-- ✅ صحيح: جلب الموظفين الذين ليس لديهم رقم هاتف ثانٍ
SELECT * FROM employees
WHERE phone2 IS NULL;
-- النتيجة:
-- | 2 | فاطمة | 6000 | NULL | NULL |
-- | 4 | سارة | 7000 | NULL | NULL |
-- ✅ صحيح: جلب الموظفين الذين لديهم رقم هاتف ثانٍ
SELECT * FROM employees
WHERE phone2 IS NOT NULL;
-- النتيجة:
-- | 1 | أحمد | 5000 | 0501234567 | NULL |
-- | 3 | محمد | 5500 | 0509876543 | 2024-12-31 |
3. استخدام IS NULL و IS NOT NULL
مثال 1: الموظفون الذين لا يزالون يعملون
SELECT name, salary FROM employees
WHERE end_date IS NULL;
+----------+--------+
| name | salary |
+----------+--------+
| أحمد | 5000 |
| فاطمة | 6000 |
| سارة | 7000 |
+----------+--------+
3 rows in set
مثال 2: المنتجات بدون خصم
+----+------------------+--------+----------+
| id | name | price | discount |
+----+------------------+--------+----------+
| 1 | لابتوب | 3500 | 10 |
| 2 | ماوس | 50 | NULL |
| 3 | شاشة | 800 | 15 |
| 4 | لوحة مفاتيح | 120 | NULL |
+----+------------------+--------+----------+
SELECT name, price FROM products
WHERE discount IS NULL;
+------------------+--------+
| name | price |
+------------------+--------+
| ماوس | 50 |
| لوحة مفاتيح | 120 |
+------------------+--------+
2 rows in set
مثال 3: دمج مع شروط أخرى
-- المنتجات الرخيصة (أقل من 200) بدون خصم
SELECT name, price FROM products
WHERE price < 200 AND discount IS NULL;
-- الموظفون النشطون براتب أعلى من 5500
SELECT name, salary FROM employees
WHERE end_date IS NULL AND salary > 5500;
4. دالة COALESCE - استبدال NULL بقيمة افتراضية
COALESCE هي دالة قوية جداً تأخذ عدة قيم وتُرجع أول قيمة غير NULL. إذا كانت جميع القيم NULL، تُرجع NULL.
COALESCE(value1, value2, value3, ..., default_value)
مثال 1: عرض "لا يوجد" بدلاً من NULL
SELECT
name,
COALESCE(phone2, 'لا يوجد') AS phone2
FROM employees;
+----------+------------+
| name | phone2 |
+----------+------------+
| أحمد | 0501234567 |
| فاطمة | لا يوجد |
| محمد | 0509876543 |
| سارة | لا يوجد |
+----------+------------+
مثال 2: حساب السعر بعد الخصم
SELECT
name,
price,
COALESCE(discount, 0) AS discount,
price - (price * COALESCE(discount, 0) / 100) AS final_price
FROM products;
+------------------+--------+----------+-------------+
| name | price | discount | final_price |
+------------------+--------+----------+-------------+
| لابتوب | 3500 | 10 | 3150.00 |
| ماوس | 50 | 0 | 50.00 |
| شاشة | 800 | 15 | 680.00 |
| لوحة مفاتيح | 120 | 0 | 120.00 |
+------------------+--------+----------+-------------+
مثال 3: أولويات متعددة
-- جدول contacts مع عدة طرق اتصال
SELECT
name,
COALESCE(mobile, phone, email, 'لا توجد معلومات اتصال') AS contact
FROM contacts;
-- سيعرض أول قيمة غير NULL من: mobile، ثم phone، ثم email
-- إذا كانت جميعها NULL، يعرض "لا توجد معلومات اتصال"
5. دالة IFNULL (MySQL) و ISNULL (SQL Server)
IFNULL في MySQL هي نسخة مبسطة من COALESCE تأخذ معاملين فقط.
-- MySQL
IFNULL(column, default_value)
-- SQL Server
ISNULL(column, default_value)
-- PostgreSQL / Oracle (استخدم COALESCE)
COALESCE(column, default_value)
مثال: IFNULL في MySQL
SELECT
name,
IFNULL(discount, 0) AS discount
FROM products;
-- مطابق لـ:
SELECT
name,
COALESCE(discount, 0) AS discount
FROM products;
COALESCE لأنها معيارية وتعمل في جميع أنظمة SQL، بينما IFNULL خاصة بـ MySQL فقط.
6. دالة NULLIF - تحويل قيمة إلى NULL
NULLIF تُرجع NULL إذا كانت القيمتان متساويتان، وإلا تُرجع القيمة الأولى.
NULLIF(value1, value2)
-- إذا كان value1 = value2، تُرجع NULL
-- وإلا تُرجع value1
مثال 1: تجنب القسمة على صفر
-- جدول sales
+----+----------+-------+
| id | product | qty |
+----+----------+-------+
| 1 | لابتوب | 10 |
| 2 | ماوس | 0 |
| 3 | شاشة | 5 |
+----+----------+-------+
-- ❌ خطأ: القسمة على صفر ستسبب خطأ
SELECT product, 1000 / qty AS price_per_unit FROM sales;
-- ✅ صحيح: استخدام NULLIF
SELECT
product,
1000 / NULLIF(qty, 0) AS price_per_unit
FROM sales;
+----------+----------------+
| product | price_per_unit |
+----------+----------------+
| لابتوب | 100.00 |
| ماوس | NULL | ← تجنب القسمة على صفر
| شاشة | 200.00 |
+----------+----------------+
مثال 2: تحويل قيم فارغة إلى NULL
-- تحويل النصوص الفارغة إلى NULL
SELECT
name,
NULLIF(email, '') AS email
FROM users;
-- إذا كان email = ''، سيتحول إلى NULL
7. NULL في العمليات الحسابية
قاعدة ذهبية: أي عملية حسابية تحتوي على NULL تُنتج NULL.
SELECT
10 + NULL AS result1, -- NULL
10 - NULL AS result2, -- NULL
10 * NULL AS result3, -- NULL
10 / NULL AS result4, -- NULL
CONCAT('Hello ', NULL) AS result5; -- NULL
مثال عملي: حساب المجموع الكلي
+----+--------+----------+
| id | price | shipping |
+----+--------+----------+
| 1 | 100 | 10 |
| 2 | 200 | NULL |
| 3 | 150 | 15 |
+----+--------+----------+
SELECT
id,
price + shipping AS total
FROM orders;
+----+-------+
| id | total |
+----+-------+
| 1 | 110 |
| 2 | NULL | ← مشكلة!
| 3 | 165 |
+----+-------+
SELECT
id,
price + COALESCE(shipping, 0) AS total
FROM orders;
+----+-------+
| id | total |
+----+-------+
| 1 | 110 |
| 2 | 200 | ← صحيح!
| 3 | 165 |
+----+-------+
8. NULL في الدوال التجميعية
الدوال التجميعية مثل COUNT, SUM, AVG تتجاهل القيم NULL تلقائياً.
+----+----------+-------+
| id | student | score |
+----+----------+-------+
| 1 | أحمد | 85 |
| 2 | فاطمة | 90 |
| 3 | محمد | NULL | ← غائب
| 4 | سارة | 95 |
| 5 | علي | NULL | ← غائب
+----+----------+-------+
SELECT
COUNT(*) AS total_students, -- 5 (كل الطلاب)
COUNT(score) AS students_attended, -- 3 (فقط من لديهم درجات)
SUM(score) AS total_score, -- 270 (85+90+95)
AVG(score) AS average_score -- 90 (270/3)
FROM scores;
+----------------+-------------------+-------------+---------------+
| total_students | students_attended | total_score | average_score |
+----------------+-------------------+-------------+---------------+
| 5 | 3 | 270 | 90.00 |
+----------------+-------------------+-------------+---------------+
-- لاحظ: AVG حسب المتوسط على 3 طلاب فقط (تجاهل NULL)
COUNT(*) يعد جميع الصفوف، بينما COUNT(column) يعد فقط الصفوف التي ليست NULL في ذلك العمود.
9. NULL في ORDER BY
عند الترتيب، سلوك NULL يختلف حسب نظام قاعدة البيانات:
| نظام SQL | ASC (تصاعدي) | DESC (تنازلي) |
|---|---|---|
| MySQL | NULL في البداية | NULL في النهاية |
| PostgreSQL | NULL في النهاية | NULL في البداية |
| SQL Server | NULL في البداية | NULL في النهاية |
التحكم في موضع NULL (PostgreSQL)
-- PostgreSQL: وضع NULL في البداية
SELECT * FROM employees
ORDER BY end_date ASC NULLS FIRST;
-- PostgreSQL: وضع NULL في النهاية
SELECT * FROM employees
ORDER BY end_date ASC NULLS LAST;
10. أمثلة عملية متقدمة
مثال 1: تقرير الموظفين الكامل
SELECT
name,
salary,
COALESCE(phone2, 'غير متوفر') AS phone2,
COALESCE(email, 'غير متوفر') AS email,
CASE
WHEN end_date IS NULL THEN 'نشط'
ELSE 'منتهي العقد'
END AS status,
COALESCE(end_date, 'لا يزال يعمل') AS end_date
FROM employees;
مثال 2: حساب الإجمالي مع الخصم
SELECT
product_name,
price,
quantity,
COALESCE(discount, 0) AS discount,
COALESCE(tax, 0) AS tax,
(price * quantity) AS subtotal,
(price * quantity) * (1 - COALESCE(discount, 0) / 100) AS after_discount,
(price * quantity) * (1 - COALESCE(discount, 0) / 100) * (1 + COALESCE(tax, 0) / 100) AS total
FROM order_items;
مثال 3: البحث مع NULL
-- البحث عن منتج: إذا كان الخصم NULL أو أكبر من 10%
SELECT * FROM products
WHERE discount IS NULL OR discount > 10;
-- البحث عن موظف: لديه رقم هاتف ثانٍ أو بريد إلكتروني
SELECT * FROM employees
WHERE phone2 IS NOT NULL OR email IS NOT NULL;
مثال 4: تنظيف البيانات
-- تحديث جميع الخصومات NULL إلى 0
UPDATE products
SET discount = 0
WHERE discount IS NULL;
-- تحديث البريد الإلكتروني الفارغ إلى NULL
UPDATE users
SET email = NULL
WHERE email = '';
11. نصائح وأفضل الممارسات
1. لا تستخدم = أو != مع NULL أبداً
-- ❌ خطأ
WHERE column = NULL
WHERE column != NULL
-- ✅ صحيح
WHERE column IS NULL
WHERE column IS NOT NULL
2. استخدم COALESCE في الحسابات
دائماً استخدم COALESCE عند إجراء عمليات حسابية على أعمدة قد تحتوي على NULL.
3. حدد القيم الافتراضية في التصميم
CREATE TABLE products (
id INT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
price DECIMAL(10,2) NOT NULL,
discount DECIMAL(5,2) DEFAULT 0, -- قيمة افتراضية بدلاً من NULL
stock INT DEFAULT 0
);
4. استخدم NOT NULL عندما يكون ذلك منطقياً
إذا كان العمود يجب أن يحتوي دائماً على قيمة، استخدم NOT NULL في تعريف الجدول.
5. وثّق سلوك NULL في قاعدة بياناتك
اكتب تعليقات توضح ماذا يعني NULL في كل عمود (غير معروف، غير متوفر، غير مطبق، إلخ).
ملخص الدرس
- NULL: تعني "غياب القيمة" أو "قيمة غير معروفة"
- المقارنة: استخدم
IS NULLوIS NOT NULL(وليس = أو !=) - COALESCE: استبدال NULL بقيمة افتراضية
- IFNULL: نسخة مبسطة من COALESCE (MySQL فقط)
- NULLIF: تحويل قيمة معينة إلى NULL
- الحسابات: أي عملية مع NULL تُنتج NULL
- الدوال التجميعية: تتجاهل NULL تلقائياً
- Best Practice: استخدم COALESCE في الحسابات وحدد قيم افتراضية
الخطوة التالية: الدوال التجميعية (Aggregate Functions)
أكمل رحلتك التعليمية وانتقل إلى الدرس التالي لتعلم الدوال التجميعية (Aggregate Functions) وتطوير مهاراتك في قواعد البيانات.
الانتقال إلى الدرس التالي