الدوال التجميعية

الدوال التجميعية

🌍 تشبيه من العالم الحقيقي

تخيل أنك مدير سوبرماركت تنظر إلى كومة من إيصالات المبيعات:

الدوال التجميعية هي "الآلات الحاسبة" في SQL، وتساعدك على حساب نتائج ملخصة بسرعة من كميات كبيرة من البيانات.


🎯 المفاهيم الأساسية

COUNT — العدّ

يُستخدم COUNT لعدّ الصفوف. هناك شكلان شائعان:

SQL
-- 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 تلقائيًا.

SQL
SELECT SUM(salary) AS total_salary FROM employees;

AVG — المتوسط

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

SQL
SELECT AVG(salary) AS avg_salary FROM employees;

MAX / MIN — الأقصى / الأدنى

يجد القيمة القصوى أو الدنيا في عمود، مع تجاهل القيم NULL تلقائيًا.

SQL
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
SQL
-- لنفترض أن جدول 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 داخل الدوال التجميعية إلى إزالة التكرار قبل التجميع:

SQL
-- كم عدد الأقسام المميزة التي لديها موظفون؟
SELECT COUNT(DISTINCT department_id) AS dept_count FROM employees;

-- مجموع جميع الرواتب المميزة (مجموع بدون تكرار)
SELECT SUM(DISTINCT salary) AS unique_salary_sum FROM employees;

📝 الصيغة الأساسية

SQL
-- الصيغة الأساسية للدالة التجميعية
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 تلقائيًا في العمليات التجميعية — هذه ميزة وفخ في نفس الوقت، لذا كن حذرًا

📌 أمثلة

مثال: إحصائيات أساسية للموظفين

SQL
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;
▶ جرّب الكود

الناتج:

TEXT
total_employees  has_email  total_salary  avg_salary  highest_salary  lowest_salary
---------------  ---------  -----------  ----------  --------------  -------------
8                7          112000.00    14000.00    20000.00        9000.00
💡 التفسير: من أصل 8 موظفين، 7 لديهم عناوين بريد إلكتروني (1 لديه بريد NULL). متوسط الراتب هو 14000.


مثال: تجميع شرطي + DISTINCT

SQL
-- كم عدد موظفي قسم التكنولوجيا؟ وكم عدد الرواتب المميزة؟
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;
▶ جرّب الكود

الناتج:

TEXT
tech_dept_count  distinct_salary_count  tech_dept_avg_salary
---------------  ---------------------  --------------------
3                3                      17666.67
💡 التفسير: قسم التكنولوجيا يحتوي على 3 موظفين برواتب مميزة، ومتوسط راتب 17666.67. يقوم WHERE أولاً بتصفية موظفي قسم التكنولوجيا، ثم يتم إجراء التجميع على النتائج المصفاة.


مثال: دوال تجميعية متعددة + تصفية شرطية

SQL
-- إحصائيات مبالغ الطلبات: الطلبات المكتملة فقط
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';
▶ جرّب الكود

الناتج:

TEXT
order_count  total_amount  avg_order_amount  largest_order  smallest_order
-----------  -----------  ----------------  -------------  --------------
5            42500.00     8500.00           15000.00       2800.00
💡 التفسير: يقوم WHERE أولاً بتصفية الطلبات المكتملة، ثم يجري العمليات التجميعية على تلك الطلبات. لاحظ أن WHERE يُنفَّذ قبل التجميع.


🎬 سيناريوهات تطبيقية

السيناريو 1: تقرير الموارد البشرية — نظرة عامة على الرواتب

تحتاج الموارد البشرية إلى تقرير لفهم الوضع العام للرواتب في الشركة وعدد الموظفين الذين لديهم معلومات اتصال.

SQL
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: تحليل المبيعات — توزيع قيمة الطلبات

تحليل توزيع قيمة جميع الطلبات المشحونة.

SQL
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) الأدنى يُتجاهل

📝 تمارين

التمرين 1 (⭐): استعلم من جدول employees لإيجاد العدد الإجمالي للموظفين، وأعلى راتب، وأقل راتب، ومتوسط الراتب.

التمرين 2 (⭐⭐): استعلم من جدول orders لإيجاد عدد الطلبات المكتملة والمبلغ الإجمالي والمتوسط لعام 2025. الشرط: عدّ فقط الطلبات ذات status = 'completed'.

التمرين 3 (⭐⭐⭐): استعلم من جدول employees لعدّ الموظفين في كل فئة راتب. القواعد: الراتب >= 15000 هو "مرتفع"، >= 10000 هو "متوسط"، والباقون هم "مبتدئين". تلميح: استخدم CASE WHEN مع الدوال التجميعية.


الدرس التالي

👉 14-group-by - استعلامات التجميع: تعلّم استعلامات التجميع GROUP BY، وإتقان الإحصائيات حسب الفئة، وتصفية المجموعات باستخدام HAVING، والمزيد!

Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%