التجميع GROUP BY
جملة GROUP BY في SQL هي واحدة من أقوى الأدوات لتحليل البيانات وتجميعها حسب فئات محددة. بدلاً من الحصول على إحصائية واحدة للجدول بأكمله، يمكنك تقسيم البيانات إلى مجموعات وحساب إحصائيات منفصلة لكل مجموعة. في هذا الدرس الشامل من سلسلة تعلم لغة SQL باللغة العربية، سنتعلم كيفية استخدام GROUP BY في SQL لتجميع البيانات، دمجها مع الدوال التجميعية في SQL، وإنشاء تقارير تحليلية احترافية لقواعد البيانات.
1. ما هو GROUP BY في SQL؟
GROUP BY هي جملة في لغة SQL تُستخدم لتجميع الصفوف التي لها نفس القيم في أعمدة محددة. عند استخدام GROUP BY في SQL، يتم تقسيم البيانات إلى مجموعات، ويمكنك تطبيق الدوال التجميعية (COUNT, SUM, AVG, MIN, MAX) على كل مجموعة بشكل منفصل.
البنية الأساسية لـ GROUP BY في SQL
SELECT column1, aggregate_function(column2)
FROM table_name
WHERE condition
GROUP BY column1
ORDER BY column1;
مثال توضيحي: الفرق بين بدون وبـ GROUP BY
+----+----------+----------+--------+
| id | product | quantity | price |
+----+----------+----------+--------+
| 1 | لابتوب | 2 | 3500 |
| 2 | ماوس | 10 | 50 |
| 3 | لابتوب | 1 | 3500 |
| 4 | شاشة | 3 | 800 |
| 5 | ماوس | 5 | 50 |
| 6 | لابتوب | 3 | 3500 |
+----+----------+----------+--------+
SELECT SUM(quantity) AS total_quantity
FROM sales;
+----------------+
| total_quantity |
+----------------+
| 24 |
+----------------+
-- مجموع كل المبيعات: 2+10+1+3+5+3 = 24
SELECT
product,
SUM(quantity) AS total_quantity
FROM sales
GROUP BY product;
+----------+----------------+
| product | total_quantity |
+----------+----------------+
| لابتوب | 6 | ← 2+1+3
| ماوس | 15 | ← 10+5
| شاشة | 3 |
+----------+----------------+
2. استخدام GROUP BY مع COUNT في SQL
أحد أكثر الاستخدامات شيوعاً لـ GROUP BY في SQL هو عد عدد العناصر في كل مجموعة باستخدام دالة COUNT.
مثال 1: عدد الموظفين في كل قسم
+----+----------+--------+------------+
| id | name | salary | department |
+----+----------+--------+------------+
| 1 | أحمد | 5000 | IT |
| 2 | فاطمة | 6000 | HR |
| 3 | محمد | 5500 | IT |
| 4 | سارة | 7000 | Sales |
| 5 | علي | 6500 | IT |
| 6 | نورة | 5800 | HR |
| 7 | خالد | 6200 | Sales |
+----+----------+--------+------------+
SELECT
department AS القسم,
COUNT(*) AS عدد_الموظفين
FROM employees
GROUP BY department
ORDER BY عدد_الموظفين DESC;
+------------+----------------+
| القسم | عدد_الموظفين |
+------------+----------------+
| IT | 3 |
| HR | 2 |
| Sales | 2 |
+------------+----------------+
مثال 2: عدد الطلبات لكل عميل
SELECT
customer_name,
COUNT(*) AS total_orders
FROM orders
GROUP BY customer_name
ORDER BY total_orders DESC;
3. استخدام GROUP BY مع SUM في SQL
يمكنك استخدام GROUP BY مع دالة SUM في SQL لحساب المجموع لكل مجموعة، مثل إجمالي المبيعات لكل منتج أو إجمالي الرواتب لكل قسم.
مثال 1: إجمالي الرواتب لكل قسم
SELECT
department,
SUM(salary) AS total_salaries,
COUNT(*) AS employee_count
FROM employees
GROUP BY department;
+------------+----------------+----------------+
| department | total_salaries | employee_count |
+------------+----------------+----------------+
| IT | 17000 | 3 | ← 5000+5500+6500
| HR | 11800 | 2 | ← 6000+5800
| Sales | 13200 | 2 | ← 7000+6200
+------------+----------------+----------------+
مثال 2: إجمالي الإيرادات لكل منتج
SELECT
product,
SUM(quantity) AS total_sold,
SUM(quantity * price) AS total_revenue
FROM sales
GROUP BY product
ORDER BY total_revenue DESC;
+----------+------------+---------------+
| product | total_sold | total_revenue |
+----------+------------+---------------+
| لابتوب | 6 | 21000 | ← 6 × 3500
| شاشة | 3 | 2400 | ← 3 × 800
| ماوس | 15 | 750 | ← 15 × 50
+----------+------------+---------------+
4. استخدام GROUP BY مع AVG في SQL
دالة AVG مع GROUP BY في SQL تُستخدم لحساب المتوسط لكل مجموعة، مثل متوسط الراتب لكل قسم أو متوسط الدرجات لكل صف دراسي.
مثال 1: متوسط الراتب لكل قسم
SELECT
department,
COUNT(*) AS employees,
AVG(salary) AS avg_salary,
MIN(salary) AS min_salary,
MAX(salary) AS max_salary
FROM employees
GROUP BY department
ORDER BY avg_salary DESC;
+------------+-----------+------------+------------+------------+
| department | employees | avg_salary | min_salary | max_salary |
+------------+-----------+------------+------------+------------+
| Sales | 2 | 6600.00 | 6200 | 7000 |
| HR | 2 | 5900.00 | 5800 | 6000 |
| IT | 3 | 5666.67 | 5000 | 6500 |
+------------+-----------+------------+------------+------------+
5. GROUP BY مع أعمدة متعددة في SQL
يمكنك استخدام GROUP BY مع عدة أعمدة في SQL لإنشاء تجميعات أكثر تفصيلاً. البيانات ستُجمع حسب كل تركيبة فريدة من القيم.
مثال: المبيعات حسب المنتج والمدينة
+----+----------+----------+----------+--------+
| id | product | city | quantity | price |
+----+----------+----------+----------+--------+
| 1 | لابتوب | الرياض | 2 | 3500 |
| 2 | لابتوب | جدة | 1 | 3500 |
| 3 | ماوس | الرياض | 10 | 50 |
| 4 | ماوس | جدة | 5 | 50 |
| 5 | لابتوب | الرياض | 3 | 3500 |
+----+----------+----------+----------+--------+
SELECT
product,
city,
SUM(quantity) AS total_quantity,
SUM(quantity * price) AS total_revenue
FROM sales_detailed
GROUP BY product, city
ORDER BY product, city;
+----------+----------+----------------+---------------+
| product | city | total_quantity | total_revenue |
+----------+----------+----------------+---------------+
| لابتوب | الرياض | 5 | 17500 |
| لابتوب | جدة | 1 | 3500 |
| ماوس | الرياض | 10 | 500 |
| ماوس | جدة | 5 | 250 |
+----------+----------+----------------+---------------+
6. دمج GROUP BY مع WHERE في SQL
يمكنك استخدام WHERE قبل GROUP BY في SQL لتصفية البيانات أولاً، ثم تجميع النتائج المفلترة فقط.
ترتيب التنفيذ في SQL
1. FROM - اختيار الجدول
2. WHERE - تصفية الصفوف
3. GROUP BY - تجميع البيانات
4. HAVING - تصفية المجموعات (سنتعلمها في الدرس القادم)
5. SELECT - اختيار الأعمدة
6. ORDER BY - ترتيب النتائج
7. LIMIT - تحديد عدد النتائج
مثال 1: الموظفون براتب أعلى من 5500 لكل قسم
SELECT
department,
COUNT(*) AS high_earners,
AVG(salary) AS avg_high_salary
FROM employees
WHERE salary > 5500
GROUP BY department;
+------------+--------------+------------------+
| department | high_earners | avg_high_salary |
+------------+--------------+------------------+
| IT | 1 | 6500.00 | ← علي فقط
| HR | 1 | 6000.00 | ← فاطمة فقط
| Sales | 2 | 6600.00 | ← سارة وخالد
+------------+--------------+------------------+
مثال 2: مبيعات 2024 لكل منتج
SELECT
product,
COUNT(*) AS orders_count,
SUM(quantity) AS total_sold
FROM sales
WHERE sale_date BETWEEN '2024-01-01' AND '2024-12-31'
GROUP BY product;
7. أمثلة عملية متقدمة لـ GROUP BY في SQL
مثال 1: تقرير المبيعات الشهري
SELECT
YEAR(order_date) AS year,
MONTH(order_date) AS month,
COUNT(*) AS total_orders,
SUM(amount) AS total_sales,
AVG(amount) AS avg_order_value
FROM orders
GROUP BY YEAR(order_date), MONTH(order_date)
ORDER BY year DESC, month DESC;
مثال 2: أفضل 5 عملاء
SELECT
customer_name,
COUNT(*) AS total_orders,
SUM(amount) AS total_spent,
AVG(amount) AS avg_order
FROM orders
GROUP BY customer_name
ORDER BY total_spent DESC
LIMIT 5;
مثال 3: تحليل الأداء الأكاديمي
SELECT
class,
COUNT(*) AS total_students,
COUNT(score) AS students_attended,
AVG(score) AS class_average,
MIN(score) AS lowest_score,
MAX(score) AS highest_score,
COUNT(CASE WHEN score >= 50 THEN 1 END) AS passed,
COUNT(CASE WHEN score < 50 THEN 1 END) AS failed
FROM exam_results
GROUP BY class
ORDER BY class_average DESC;
مثال 4: تحليل المخزون
SELECT
category,
COUNT(*) AS product_count,
SUM(stock) AS total_stock,
AVG(price) AS avg_price,
SUM(stock * price) AS inventory_value
FROM products
GROUP BY category
ORDER BY inventory_value DESC;
مثال 5: تقرير الموارد البشرية
SELECT
department,
COUNT(*) AS employees,
SUM(salary) AS payroll,
AVG(salary) AS avg_salary,
MIN(salary) AS min_salary,
MAX(salary) AS max_salary,
MAX(salary) - MIN(salary) AS salary_range,
AVG(YEAR(CURDATE()) - YEAR(hire_date)) AS avg_tenure
FROM employees
WHERE status = 'active'
GROUP BY department
ORDER BY payroll DESC;
8. الأخطاء الشائعة في GROUP BY
خطأ 1: عمود في SELECT ليس في GROUP BY
-- ❌ خطأ: name ليس في GROUP BY ولا في دالة تجميعية
SELECT name, department, AVG(salary)
FROM employees
GROUP BY department;
-- ERROR: Column 'name' is not in GROUP BY clause
-- ✅ صحيح: فقط الأعمدة في GROUP BY أو الدوال التجميعية
SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department;
-- أو إذا أردت الأسماء أيضاً:
SELECT name, department, salary
FROM employees
ORDER BY department;
خطأ 2: استخدام WHERE بدلاً من HAVING
-- ❌ خطأ: لا يمكن استخدام دالة تجميعية في WHERE
SELECT department, AVG(salary) AS avg_salary
FROM employees
WHERE AVG(salary) > 6000
GROUP BY department;
-- ERROR: Invalid use of aggregate function
-- ✅ صحيح: استخدم HAVING لتصفية المجموعات
SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department
HAVING AVG(salary) > 6000;
-- سنتعلم HAVING بالتفصيل في الدرس القادم
خطأ 3: نسيان GROUP BY مع الدوال التجميعية
9. نصائح وأفضل الممارسات لـ GROUP BY في SQL
1. استخدم أسماء واضحة مع AS
-- سيء
SELECT department, COUNT(*), AVG(salary)
FROM employees
GROUP BY department;
-- جيد
SELECT
department AS القسم,
COUNT(*) AS عدد_الموظفين,
AVG(salary) AS متوسط_الراتب
FROM employees
GROUP BY department;
2. رتب النتائج بـ ORDER BY
دائماً استخدم ORDER BY بعد GROUP BY في SQL لترتيب النتائج بشكل منطقي.
3. استخدم ROUND مع AVG
SELECT
department,
ROUND(AVG(salary), 2) AS avg_salary
FROM employees
GROUP BY department;
4. اجمع إحصائيات متعددة في استعلام واحد
بدلاً من تشغيل عدة استعلامات SQL منفصلة، اجمع كل الإحصائيات في استعلام GROUP BY واحد.
5. انتبه لترتيب الأعمدة في GROUP BY
عند استخدام GROUP BY مع عدة أعمدة في SQL، ترتيب الأعمدة لا يؤثر على النتيجة، لكن يُفضل ترتيبها منطقياً.
ملخص الدرس
- GROUP BY في SQL: تُستخدم لتجميع الصفوف حسب قيم محددة
- الدوال التجميعية: COUNT, SUM, AVG, MIN, MAX تعمل على كل مجموعة
- القاعدة الذهبية: كل عمود في SELECT يجب أن يكون في GROUP BY أو دالة تجميعية
- أعمدة متعددة: يمكن استخدام GROUP BY مع عدة أعمدة للتجميع التفصيلي
- مع WHERE: WHERE تُصفي قبل التجميع، HAVING تُصفي بعد التجميع
- ترتيب التنفيذ: FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT
- Best Practice: استخدم أسماء واضحة، رتب النتائج، واجمع إحصائيات متعددة
الخطوة التالية: شرط HAVING
أكمل رحلتك التعليمية وانتقل إلى الدرس التالي لتعلم شرط HAVING وتطوير مهاراتك في قواعد البيانات.
الانتقال إلى الدرس التالي