الدوال التجميعية (Aggregate Functions)

الدوال التجميعية (Aggregate Functions) هي من أقوى الأدوات في SQL لتحليل البيانات واستخراج إحصائيات مفيدة. بدلاً من التعامل مع كل صف على حدة، تسمح لك هذه الدوال بإجراء عمليات حسابية على مجموعات كاملة من البيانات. في هذا الدرس الشامل من سلسلة تعلم لغة SQL باللغة العربية، سنتعلم الدوال الخمس الأساسية: COUNT (العد)، SUM (المجموع)، AVG (المتوسط)، MIN (الأصغر)، وMAX (الأكبر)، مع أمثلة عملية واقعية من عالم الأعمال.

1. ما هي الدوال التجميعية؟

الدوال التجميعية (Aggregate Functions) هي دوال خاصة في SQL تعمل على مجموعة من الصفوف وتُرجع قيمة واحدة. بدلاً من معالجة كل صف بشكل منفصل، تقوم هذه الدوال بتجميع البيانات وحساب نتيجة واحدة.

الدوال التجميعية الأساسية الخمس
الدالة الوصف مثال
COUNT() عد عدد الصفوف كم عدد الموظفين؟
SUM() حساب المجموع ما مجموع المبيعات؟
AVG() حساب المتوسط ما متوسط الرواتب؟
MIN() إيجاد أصغر قيمة ما أقل سعر؟
MAX() إيجاد أكبر قيمة ما أعلى درجة؟
ملاحظة مهمة: الدوال التجميعية تتجاهل القيم NULL تلقائياً (ما عدا COUNT(*)).

2. دالة COUNT - عد الصفوف

COUNT() تُستخدم لعد عدد الصفوف. لها ثلاث صيغ مختلفة:

صيغ COUNT المختلفة
COUNT(*)              -- عد جميع الصفوف (بما فيها NULL)
COUNT(column_name)    -- عد الصفوف التي ليست NULL في هذا العمود
COUNT(DISTINCT column_name)  -- عد القيم الفريدة (بدون تكرار)
مثال: جدول الموظفين
جدول employees
+----+----------+--------+------------+
| id | name     | salary | department |
+----+----------+--------+------------+
| 1  | أحمد     | 5000   | IT         |
| 2  | فاطمة    | 6000   | HR         |
| 3  | محمد     | 5500   | IT         |
| 4  | سارة     | 7000   | NULL       |
| 5  | علي      | 6500   | IT         |
| 6  | نورة     | 5800   | HR         |
+----+----------+--------+------------+
مثال 1: COUNT(*) - عد جميع الموظفين
عد جميع الصفوف
SELECT COUNT(*) AS total_employees
FROM employees;
النتيجة
+-----------------+
| total_employees |
+-----------------+
| 6               |
+-----------------+
مثال 2: COUNT(column) - عد الموظفين الذين لديهم قسم
عد القيم غير NULL
SELECT 
    COUNT(*) AS total_employees,
    COUNT(department) AS employees_with_department
FROM employees;
النتيجة
+-----------------+--------------------------+
| total_employees | employees_with_department|
+-----------------+--------------------------+
| 6               | 5                        |
+-----------------+--------------------------+

-- سارة ليس لديها قسم (NULL)، لذلك لم تُحسب
مثال 3: COUNT(DISTINCT) - عد الأقسام الفريدة
عد القيم الفريدة
SELECT COUNT(DISTINCT department) AS unique_departments
FROM employees;
النتيجة
+---------------------+
| unique_departments  |
+---------------------+
| 2                   |
+---------------------+

-- الأقسام: IT, HR (بدون تكرار)

3. دالة SUM - حساب المجموع

SUM() تحسب مجموع القيم في عمود رقمي. تتجاهل القيم NULL تلقائياً.

مثال 1: مجموع الرواتب
إجمالي الرواتب
SELECT SUM(salary) AS total_salaries
FROM employees;
النتيجة
+----------------+
| total_salaries |
+----------------+
| 35800          |
+----------------+

-- 5000 + 6000 + 5500 + 7000 + 6500 + 5800 = 35800
مثال 2: جدول المبيعات
جدول sales
+----+------------+----------+--------+
| id | product    | quantity | price  |
+----+------------+----------+--------+
| 1  | لابتوب     | 2        | 3500   |
| 2  | ماوس       | 10       | 50     |
| 3  | شاشة       | 3        | 800    |
| 4  | لوحة مفاتيح| 5        | 120    |
+----+------------+----------+--------+
إجمالي المبيعات
SELECT 
    SUM(quantity) AS total_items_sold,
    SUM(quantity * price) AS total_revenue
FROM sales;
النتيجة
+------------------+---------------+
| total_items_sold | total_revenue |
+------------------+---------------+
| 20               | 10500         |
+------------------+---------------+

-- الكمية: 2+10+3+5 = 20
-- الإيرادات: (2×3500)+(10×50)+(3×800)+(5×120) = 10500

4. دالة AVG - حساب المتوسط

AVG() تحسب المتوسط الحسابي للقيم في عمود رقمي. تتجاهل NULL تلقائياً.

مثال 1: متوسط الرواتب
المتوسط الحسابي
SELECT AVG(salary) AS average_salary
FROM employees;
النتيجة
+----------------+
| average_salary |
+----------------+
| 5966.67        |
+----------------+

-- 35800 / 6 = 5966.67
مثال 2: جدول الدرجات
جدول grades
+----+----------+-------+
| id | student  | score |
+----+----------+-------+
| 1  | أحمد     | 85    |
| 2  | فاطمة    | 92    |
| 3  | محمد     | 78    |
| 4  | سارة     | 95    |
| 5  | علي      | NULL  | ← غائب
+----+----------+-------+
متوسط الدرجات
SELECT 
    COUNT(*) AS total_students,
    COUNT(score) AS students_attended,
    AVG(score) AS average_score
FROM grades;
النتيجة
+----------------+-------------------+---------------+
| total_students | students_attended | average_score |
+----------------+-------------------+---------------+
| 5              | 4                 | 87.50         |
+----------------+-------------------+---------------+

-- المتوسط: (85+92+78+95) / 4 = 87.50
-- لاحظ: تم تجاهل NULL (علي غائب)
تحذير: AVG تتجاهل NULL، لذلك المتوسط يُحسب فقط على القيم الموجودة. إذا أردت اعتبار NULL كصفر، استخدم AVG(COALESCE(column, 0))

5. دالة MIN - إيجاد أصغر قيمة

MIN() تُرجع أصغر قيمة في عمود. تعمل مع الأرقام، النصوص، والتواريخ.

مثال 1: أقل راتب
الحد الأدنى
SELECT MIN(salary) AS lowest_salary
FROM employees;
النتيجة
+---------------+
| lowest_salary |
+---------------+
| 5000          |
+---------------+
مثال 2: MIN مع التواريخ
جدول orders
+----+------------+------------+
| id | customer   | order_date |
+----+------------+------------+
| 1  | أحمد       | 2024-01-15 |
| 2  | فاطمة      | 2024-01-10 |
| 3  | محمد       | 2024-01-20 |
+----+------------+------------+
أول وآخر طلب
SELECT 
    MIN(order_date) AS first_order,
    MAX(order_date) AS last_order
FROM orders;
النتيجة
+-------------+------------+
| first_order | last_order |
+-------------+------------+
| 2024-01-10  | 2024-01-20 |
+-------------+------------+

6. دالة MAX - إيجاد أكبر قيمة

MAX() تُرجع أكبر قيمة في عمود. تعمل مع الأرقام، النصوص، والتواريخ.

مثال 1: أعلى راتب
الحد الأقصى
SELECT MAX(salary) AS highest_salary
FROM employees;
النتيجة
+----------------+
| highest_salary |
+----------------+
| 7000           |
+----------------+
مثال 2: دمج جميع الدوال
تقرير شامل للرواتب
SELECT 
    COUNT(*) AS total_employees,
    SUM(salary) AS total_salaries,
    AVG(salary) AS average_salary,
    MIN(salary) AS lowest_salary,
    MAX(salary) AS highest_salary
FROM employees;
النتيجة
+-----------------+----------------+----------------+---------------+----------------+
| total_employees | total_salaries | average_salary | lowest_salary | highest_salary |
+-----------------+----------------+----------------+---------------+----------------+
| 6               | 35800          | 5966.67        | 5000          | 7000           |
+-----------------+----------------+----------------+---------------+----------------+

7. دمج الدوال التجميعية مع WHERE

يمكنك استخدام WHERE لتصفية البيانات قبل تطبيق الدوال التجميعية.

مثال 1: إحصائيات قسم IT فقط
تصفية ثم تجميع
SELECT 
    COUNT(*) AS it_employees,
    AVG(salary) AS it_avg_salary
FROM employees
WHERE department = 'IT';
النتيجة
+--------------+----------------+
| it_employees | it_avg_salary  |
+--------------+----------------+
| 3            | 5666.67        |
+--------------+----------------+

-- موظفو IT: أحمد (5000)، محمد (5500)، علي (6500)
-- المتوسط: (5000+5500+6500) / 3 = 5666.67
مثال 2: المبيعات في يناير 2024
تقرير شهري
SELECT 
    COUNT(*) AS total_orders,
    SUM(amount) AS total_sales,
    AVG(amount) AS average_order
FROM orders
WHERE order_date BETWEEN '2024-01-01' AND '2024-01-31';

8. أمثلة عملية متقدمة

مثال 1: تقرير المخزون
تحليل المخزون
SELECT 
    COUNT(*) AS total_products,
    SUM(stock) AS total_items_in_stock,
    AVG(price) AS average_price,
    MIN(price) AS cheapest_product,
    MAX(price) AS most_expensive_product,
    SUM(stock * price) AS total_inventory_value
FROM products;
مثال 2: تقرير الأداء الأكاديمي
إحصائيات الامتحان
SELECT 
    COUNT(*) AS total_students,
    COUNT(score) AS students_attended,
    COUNT(*) - COUNT(score) AS students_absent,
    AVG(score) AS class_average,
    MIN(score) AS lowest_score,
    MAX(score) AS highest_score,
    MAX(score) - MIN(score) AS score_range
FROM exam_results;
مثال 3: تحليل المبيعات اليومية
KPIs المبيعات
SELECT 
    COUNT(DISTINCT customer_id) AS unique_customers,
    COUNT(*) AS total_transactions,
    SUM(amount) AS total_revenue,
    AVG(amount) AS average_transaction,
    MIN(amount) AS smallest_sale,
    MAX(amount) AS largest_sale
FROM daily_sales
WHERE sale_date = CURDATE();
مثال 4: تقرير الموارد البشرية
ملخص الموظفين
SELECT 
    COUNT(*) AS total_employees,
    COUNT(DISTINCT department) AS total_departments,
    SUM(salary) AS monthly_payroll,
    AVG(salary) AS average_salary,
    MIN(hire_date) AS first_hire,
    MAX(hire_date) AS latest_hire,
    AVG(YEAR(CURDATE()) - YEAR(hire_date)) AS avg_years_of_service
FROM employees
WHERE status = 'active';

9. استخدام ROUND مع الدوال التجميعية

غالباً ما تُنتج AVG أرقاماً عشرية طويلة. يمكنك استخدام ROUND() لتقريب النتيجة.

تقريب النتائج
SELECT 
    AVG(salary) AS avg_raw,
    ROUND(AVG(salary)) AS avg_rounded,
    ROUND(AVG(salary), 2) AS avg_two_decimals
FROM employees;
النتيجة
+-------------+--------------+------------------+
| avg_raw     | avg_rounded  | avg_two_decimals |
+-------------+--------------+------------------+
| 5966.666667 | 5967         | 5966.67          |
+-------------+--------------+------------------+

10. الأخطاء الشائعة وكيفية تجنبها

خطأ 1: خلط الأعمدة العادية مع الدوال التجميعية
❌ خطأ شائع
-- ❌ خطأ: لا يمكن خلط أعمدة عادية مع دوال تجميعية بدون GROUP BY
SELECT name, AVG(salary)
FROM employees;

-- ERROR: Column 'name' is not in GROUP BY clause
✅ الحل
-- ✅ صحيح: استخدم فقط الدوال التجميعية
SELECT AVG(salary) AS average_salary
FROM employees;

-- أو استخدم GROUP BY (سنتعلمها في الدرس القادم)
SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department;
خطأ 2: نسيان أن الدوال تتجاهل NULL
تذكر: COUNT(column) يختلف عن COUNT(*). الأول يتجاهل NULL، والثاني يعد كل الصفوف.
خطأ 3: استخدام SUM على نصوص
❌ خطأ
-- ❌ خطأ: SUM تعمل فقط على الأرقام
SELECT SUM(name) FROM employees;

-- ✅ صحيح: استخدم COUNT للعد
SELECT COUNT(name) FROM employees;

11. نصائح وأفضل الممارسات

1. استخدم أسماء واضحة للأعمدة (AS)
أسماء واضحة
-- سيء: غير واضح
SELECT COUNT(*), AVG(salary) FROM employees;

-- جيد: واضح ومفهوم
SELECT 
    COUNT(*) AS total_employees,
    AVG(salary) AS average_salary
FROM employees;
2. انتبه للقيم NULL

دائماً تحقق من كيفية تعامل الدوال مع NULL، واستخدم COALESCE إذا لزم الأمر.

3. استخدم DISTINCT بحذر

COUNT(DISTINCT column) مفيد، لكنه قد يكون بطيئاً على الجداول الكبيرة.

4. قرّب النتائج للوضوح

استخدم ROUND() مع AVG للحصول على أرقام أكثر قابلية للقراءة.

5. اجمع عدة إحصائيات في استعلام واحد

بدلاً من تشغيل 5 استعلامات منفصلة، اجمعها في استعلام واحد لتحسين الأداء.

ملخص الدرس
  • COUNT(): عد الصفوف (COUNT(*) يعد الكل، COUNT(column) يتجاهل NULL)
  • SUM(): حساب مجموع القيم الرقمية
  • AVG(): حساب المتوسط الحسابي
  • MIN(): إيجاد أصغر قيمة
  • MAX(): إيجاد أكبر قيمة
  • NULL: جميع الدوال تتجاهل NULL (ما عدا COUNT(*))
  • WHERE: يمكن استخدامها قبل الدوال التجميعية للتصفية
  • Best Practice: استخدم AS لأسماء واضحة، وROUND للتقريب

الخطوة التالية: التجميع GROUP BY

أكمل رحلتك التعليمية وانتقل إلى الدرس التالي لتعلم التجميع GROUP BY وتطوير مهاراتك في قواعد البيانات.

الانتقال إلى الدرس التالي
المحرر الذكي

اكتب الكود وشاهد النتيجة فوراً

جرب الآن مجاناً
قناة ديف عربي

تابع أحدث الدروس والتحديثات مباشرة على واتساب

انضم الآن