الدوال التجميعية
الدوال التجميعية
🌍 تشبيه من العالم الحقيقي
تخيل أنك مدير سوبرماركت تنظر إلى كومة من إيصالات المبيعات:
- COUNT = عدّ عدد الإيصالات الموجودة اليوم (العد)
- SUM = جمع المبالغ من جميع الإيصالات (الجمع)
- AVG = حساب متوسط المبلغ لكل إيصال (المتوسط)
- MAX = إيجاد الإيصال الذي يحتوي على أعلى مبلغ (الأقصى)
- MIN = إيجاد الإيصال الذي يحتوي على أقل مبلغ (الأدنى)
الدوال التجميعية هي "الآلات الحاسبة" في SQL، وتساعدك على حساب نتائج ملخصة بسرعة من كميات كبيرة من البيانات.
🎯 المفاهيم الأساسية
COUNT — العدّ
يُستخدم COUNT لعدّ الصفوف. هناك شكلان شائعان:
-- COUNT(*): عدّ جميع الصفوف (بما في ذلك الصفوف التي تحتوي على NULL)
SELECT COUNT(*) AS total_employees FROM employees;
-- COUNT(column_name): عدّ الصفوف التي لا تحتوي العمود على NULL
SELECT COUNT(email) AS has_email FROM employees;
| الصيغة | الوصف |
|---|---|
COUNT(*) |
عدّ جميع الصفوف، بغض النظر عن NULL |
COUNT(column_name) |
عدّ الصفوف التي لا يحتوي العمود على NULL فقط |
COUNT(DISTINCT column_name) |
عدّ القيم المميزة غير NULL في العمود |
SUM — الجمع
يحسب المجموع لعمود رقمي، مع تجاهل القيم NULL تلقائيًا.
SELECT SUM(salary) AS total_salary FROM employees;
AVG — المتوسط
يحسب المتوسط لعمود رقمي، مع تجاهل القيم NULL تلقائيًا (لا تُدرج القيم NULL في الحساب).
SELECT AVG(salary) AS avg_salary FROM employees;
MAX / MIN — الأقصى / الأدنى
يجد القيمة القصوى أو الدنيا في عمود، مع تجاهل القيم NULL تلقائيًا.
SELECT MAX(salary) AS highest, MIN(salary) AS lowest FROM employees;
الدوال التجميعية والتعامل مع NULL
هذا هو الفخ الأكثر شيوعًا للمبتدئين:
| الدالة | كيفية التعامل مع NULL |
|---|---|
COUNT(*) |
يُحتسب NULL (يعدّ الصفوف) |
COUNT(column_name) |
يتجاهل NULL |
SUM(column_name) |
يتجاهل NULL |
AVG(column_name) |
يتجاهل NULL (تُستبعد من المقام) |
MAX(column_name) |
يتجاهل NULL |
MIN(column_name) |
يتجاهل NULL |
-- لنفترض أن جدول employees يحتوي على 10 صفوف، مع 3 قيم NULL في عمود email
SELECT COUNT(*) AS total, -- 10
COUNT(email) AS has_email -- 7
FROM employees;
AVG، المقام هو عدد الصفوف غير NULL، وليس العدد الإجمالي للصفوف. إذا كان لدى 2 من 5 موظفين رواتب NULL، فإن AVG(salary) يحسب المتوسط باستخدام الرواتب الـ 3 غير NULL فقط.
إزالة التكرار باستخدام DISTINCT في الدوال التجميعية
يؤدي استخدام DISTINCT داخل الدوال التجميعية إلى إزالة التكرار قبل التجميع:
-- كم عدد الأقسام المميزة التي لديها موظفون؟
SELECT COUNT(DISTINCT department_id) AS dept_count FROM employees;
-- مجموع جميع الرواتب المميزة (مجموع بدون تكرار)
SELECT SUM(DISTINCT salary) AS unique_salary_sum FROM employees;
📝 الصيغة الأساسية
-- الصيغة الأساسية للدالة التجميعية
SELECT aggregate_function(column_name) AS alias
FROM table_name
WHERE condition;
-- يمكن استخدام عدة دوال تجميعية في نفس الوقت
SELECT COUNT(*) AS total_count,
SUM(column_name) AS total_sum,
AVG(column_name) AS average,
MAX(column_name) AS maximum,
MIN(column_name) AS minimum
FROM table_name;
-- إزالة التكرار باستخدام DISTINCT في التجميع
SELECT COUNT(DISTINCT column_name) AS distinct_count
FROM table_name;
- تُستخدم الدوال التجميعية عادةً مع
GROUP BY(يُغطى في الدرس التالي)، ولكن يمكن استخدامها بمفردها (تجميع الجدول بالكامل) - لا يمكن استخدام الدوال التجميعية مباشرة في شروط
WHERE— استخدمHAVINGبدلاً من ذلك (يُغطى لاحقًا) - يتم تخطي
NULLتلقائيًا في العمليات التجميعية — هذه ميزة وفخ في نفس الوقت، لذا كن حذرًا
📌 أمثلة
مثال: إحصائيات أساسية للموظفين
SELECT COUNT(*) AS total_employees,
COUNT(email) AS has_email,
SUM(salary) AS total_salary,
AVG(salary) AS avg_salary,
MAX(salary) AS highest_salary,
MIN(salary) AS lowest_salary
FROM employees;
الناتج:
total_employees has_email total_salary avg_salary highest_salary lowest_salary
--------------- --------- ----------- ---------- -------------- -------------
8 7 112000.00 14000.00 20000.00 9000.00
مثال: تجميع شرطي + DISTINCT
-- كم عدد موظفي قسم التكنولوجيا؟ وكم عدد الرواتب المميزة؟
SELECT COUNT(*) AS tech_dept_count,
COUNT(DISTINCT salary) AS distinct_salary_count,
AVG(salary) AS tech_dept_avg_salary
FROM employees
WHERE department_id = 1;
الناتج:
tech_dept_count distinct_salary_count tech_dept_avg_salary
--------------- --------------------- --------------------
3 3 17666.67
WHERE أولاً بتصفية موظفي قسم التكنولوجيا، ثم يتم إجراء التجميع على النتائج المصفاة.
مثال: دوال تجميعية متعددة + تصفية شرطية
-- إحصائيات مبالغ الطلبات: الطلبات المكتملة فقط
SELECT COUNT(*) AS order_count,
SUM(total_amount) AS total_amount,
AVG(total_amount) AS avg_order_amount,
MAX(total_amount) AS largest_order,
MIN(total_amount) AS smallest_order
FROM orders
WHERE status = 'completed';
الناتج:
order_count total_amount avg_order_amount largest_order smallest_order
----------- ----------- ---------------- ------------- --------------
5 42500.00 8500.00 15000.00 2800.00
WHERE أولاً بتصفية الطلبات المكتملة، ثم يجري العمليات التجميعية على تلك الطلبات. لاحظ أن WHERE يُنفَّذ قبل التجميع.
🎬 سيناريوهات تطبيقية
السيناريو 1: تقرير الموارد البشرية — نظرة عامة على الرواتب
تحتاج الموارد البشرية إلى تقرير لفهم الوضع العام للرواتب في الشركة وعدد الموظفين الذين لديهم معلومات اتصال.
SELECT
COUNT(*) AS total_headcount,
COUNT(email) + COUNT(phone) AS total_contacts,
SUM(salary) AS annual_salary_expense,
AVG(salary) AS avg_monthly_salary,
MAX(salary) - MIN(salary) AS max_salary_gap
FROM employees
WHERE hire_date >= '2024-01-01';
WHERE لتصفية الموظفين الذين تم تعيينهم بعد عام 2024، ثم استخدم دوال تجميعية متعددة لتلخيص البيانات من أبعاد مختلفة.
السيناريو 2: تحليل المبيعات — توزيع قيمة الطلبات
تحليل توزيع قيمة جميع الطلبات المشحونة.
SELECT
COUNT(*) AS shipped_order_count,
COUNT(DISTINCT customer_id) AS unique_customer_count,
SUM(total_amount) AS total_sales,
AVG(total_amount) AS avg_order_value,
MAX(total_amount) AS largest_order,
MIN(total_amount) AS smallest_order
FROM orders
WHERE status = 'shipped';
COUNT(DISTINCT customer_id) في فهم عدد العملاء الفريدين الذين قدموا طلبات، وليس فقط عدد الطلبات.
❓ أسئلة شائعة
س: هل هناك فرق بين COUNT(*) و COUNT(1)? ج: في قواعد البيانات الحديثة لا يوجد فرق عملي — يتعامل معهما المُحسِّن بنفس خطة التنفيذ.
COUNT(*)هو الصيغة الأكثر معيارية ويُوصى بها.
س: كيف يتعامل AVG مع NULL? ج: يتجاهل
AVGالقيم NULL. إذا كان لدى 2 من 5 موظفين رواتب NULL، فإنAVG(salary)يحسب باستخدام الرواتب الـ 3 غير NULL فقط، دون القسمة على 5. لمعاملة NULL كـ 0، استخدمAVG(COALESCE(salary, 0)).
س: هل يمكن تداخل الدوال التجميعية? ج: لا يمكن ذلك بشكل مباشر. على سبيل المثال،
MAX(AVG(salary))سيُسبب خطأ. للعثور على "القسم الذي لديه أعلى متوسط راتب"، استخدمGROUP BY+ORDER BY AVG(salary) DESC LIMIT 1، أو استخدم استعلامًا فرعيًا.
س: ماذا يُرجع SUM لجدول فارغ? ج: يُرجع
SUMوAVGوMAXوMINالقيمةNULLلجدول فارغ أو عندما تكون جميع القيم NULL، وليس 0. يُرجعCOUNTالقيمة 0. لإرجاع 0 بدلاً من ذلك، استخدمCOALESCE(SUM(column_name), 0).
📖 ملخص
| الدالة | الغرض | التعامل مع NULL | يعمل مع DISTINCT |
|---|---|---|---|
| COUNT(*) | عدّ جميع الصفوف | يُحتسب | لا ينطبق |
| COUNT(col) | عدّ الصفوف غير NULL | يُتجاهل | ✅ |
| SUM(col) | المجموع | يُتجاهل | ✅ |
| AVG(col) | المتوسط | يُتجاهل (يُستبعد من المقام) | ✅ |
| MAX(col) | الأقصى | يُتجاهل | ✅ |
| MIN(col) | الأدنى | يُتجاهل | ✅ |
- الدوال التجميعية هي "أدوات الإحصاء" في SQL التي تضغط عدة صفوف إلى قيمة ملخصة واحدة
- تتجاهل الدوال التجميعية القيم NULL تلقائيًا، باستثناء
COUNT(*) - يمكن لـ
DISTINCTإزالة التكرار قبل التجميع - لا يمكن استخدام الدوال التجميعية في
WHERE— استخدمHAVINGبدلاً من ذلك (يُغطى في الدرس التالي)
📝 تمارين
التمرين 1 (⭐): استعلم من جدول employees لإيجاد العدد الإجمالي للموظفين، وأعلى راتب، وأقل راتب، ومتوسط الراتب.
التمرين 2 (⭐⭐): استعلم من جدول orders لإيجاد عدد الطلبات المكتملة والمبلغ الإجمالي والمتوسط لعام 2025. الشرط: عدّ فقط الطلبات ذات status = 'completed'.
التمرين 3 (⭐⭐⭐): استعلم من جدول employees لعدّ الموظفين في كل فئة راتب. القواعد: الراتب >= 15000 هو "مرتفع"، >= 10000 هو "متوسط"، والباقون هم "مبتدئين". تلميح: استخدم CASE WHEN مع الدوال التجميعية.
الدرس التالي
👉 14-group-by - استعلامات التجميع: تعلّم استعلامات التجميع GROUP BY، وإتقان الإحصائيات حسب الفئة، وتصفية المجموعات باستخدام HAVING، والمزيد!



