الدوال التجميعية (Aggregate Functions)
الدوال التجميعية (Aggregate Functions) هي من أقوى الأدوات في SQL لتحليل البيانات واستخراج إحصائيات مفيدة. بدلاً من التعامل مع كل صف على حدة، تسمح لك هذه الدوال بإجراء عمليات حسابية على مجموعات كاملة من البيانات. في هذا الدرس الشامل من سلسلة تعلم لغة SQL باللغة العربية، سنتعلم الدوال الخمس الأساسية: COUNT (العد)، SUM (المجموع)، AVG (المتوسط)، MIN (الأصغر)، وMAX (الأكبر)، مع أمثلة عملية واقعية من عالم الأعمال.
1. ما هي الدوال التجميعية؟
الدوال التجميعية (Aggregate Functions) هي دوال خاصة في SQL تعمل على مجموعة من الصفوف وتُرجع قيمة واحدة. بدلاً من معالجة كل صف بشكل منفصل، تقوم هذه الدوال بتجميع البيانات وحساب نتيجة واحدة.
الدوال التجميعية الأساسية الخمس
| الدالة | الوصف | مثال |
|---|---|---|
COUNT() |
عد عدد الصفوف | كم عدد الموظفين؟ |
SUM() |
حساب المجموع | ما مجموع المبيعات؟ |
AVG() |
حساب المتوسط | ما متوسط الرواتب؟ |
MIN() |
إيجاد أصغر قيمة | ما أقل سعر؟ |
MAX() |
إيجاد أكبر قيمة | ما أعلى درجة؟ |
2. دالة COUNT - عد الصفوف
COUNT() تُستخدم لعد عدد الصفوف. لها ثلاث صيغ مختلفة:
COUNT(*) -- عد جميع الصفوف (بما فيها NULL)
COUNT(column_name) -- عد الصفوف التي ليست NULL في هذا العمود
COUNT(DISTINCT column_name) -- عد القيم الفريدة (بدون تكرار)
مثال: جدول الموظفين
+----+----------+--------+------------+
| 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) - عد الموظفين الذين لديهم قسم
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: جدول المبيعات
+----+------------+----------+--------+
| 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: جدول الدرجات
+----+----------+-------+
| 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(COALESCE(column, 0))
5. دالة MIN - إيجاد أصغر قيمة
MIN() تُرجع أصغر قيمة في عمود. تعمل مع الأرقام، النصوص، والتواريخ.
مثال 1: أقل راتب
SELECT MIN(salary) AS lowest_salary
FROM employees;
+---------------+
| lowest_salary |
+---------------+
| 5000 |
+---------------+
مثال 2: MIN مع التواريخ
+----+------------+------------+
| 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: تحليل المبيعات اليومية
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
خطأ 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 وتطوير مهاراتك في قواعد البيانات.
الانتقال إلى الدرس التالي