في هذا الدرس 6تصفّح المواضيع
تتطلب معظم التقارير المالية والإدارية عرض مجاميع كل فئة متبوعةً بصف المجموع العام الكلي في نهاية التقرير. بدلاً من تنفيذ استعلامين منفصلين، يمكنك إلحاق العبارة WITH ROLLUP مباشرةً بعد جملة GROUP BY.
- صف التجميع الفائق (Super-Aggregate): عند التجميع بعمود واحد مثل
GROUP BY category WITH ROLLUP، يعرض MySQL صفوف الفئات المعتادة ثم يضيف صفاً أخيراً يمثّل الإجمالي العام لكل الفئات. - علامة
NULLفي عمود التجميع: يضع المحرك القيمةNULLفي عمود التجميع داخل صف المجموع العام، بينما تعرض الدوال التجميعيةCOUNTوSUMوAVGحصيلة الجدول الكلي.
يحسب محرك MySQL صفوف WITH ROLLUP أثناء المسحة التجميعية نفسها دون إعادة قراءة الجدول من القرص.
المجاميع التراكمية WITH ROLLUP ودالة GROUPING وترتيب تنفيذ الاستعلام
-- Category totals plus automatic Grand Total row at the end
SELECT category,
COUNT(*) AS items_count,
SUM(stock_qty) AS total_units
FROM products
WHERE is_active = 1
GROUP BY category WITH ROLLUP;
عند التجميع بعدة أعمدة، يولّد WITH ROLLUP المجاميع الفرعية تدريجياً من اليمين إلى اليسار عبر مستويات الهرم التجميعي:
- المستوى الأول (صفوف التفصيل): في
GROUP BY region, city WITH ROLLUPتظهر أولاً مجاميع كل مدينة داخل إقليمها. - المستوى الثاني (المجموع الفرعي للإقليم): يتحول العمود الأيمن
cityإلىNULLلإنتاج صف المجموع الفرعي الخاص بكل إقليم(region, NULL). - المستوى الثالث (المجموع العام الكلي): في النهاية يتحول العمودان معاً إلى
(NULL, NULL)لإنتاج صف المجموع العام الكلي لجميع الأقاليم والمدن!
لذلك احرص دائماً على ترتيب أعمدة GROUP BY من المستوى الأوسع (كالإقليم أو السنة) على اليسار إلى المستوى الأدق (كالمدينة أو الشهر) على اليمين.
-- Multi-level rollup: per (dept, role), per dept, and grand total
SELECT dept_id,
job_role,
COUNT(*) AS headcount,
SUM(salary) AS payroll_usd
FROM employees
WHERE is_active = 1
GROUP BY dept_id, job_role WITH ROLLUP;
ماذا يحدث إذا كان عمود التجميع نفسه يقبل القيم الفارغة ويحتوي فعلياً على صفوف NULL في الجدول؟ سيظهر NULL في صف البيانات الفعلي وفي صف المجموع العام معاً! يعالج MySQL 8 هذا الالتباس عبر الدالة القياسية GROUPING(expr):
- القيمة
0: تعني أن الصف يمثّل مجموعة بيانات عادية (حتى لو كانت قيمة العمود الأصلية المسجلة في الجدول هيNULL). - القيمة
1: تعني أن القيمةNULLالظاهرة في العمود هي علامة مجموع فرعي أو كلي ولّدتها ميزةWITH ROLLUP.
يمكنك استخدام GROUPING(col) في قائمة SELECT أو في ORDER BY لدفع صفوف المجاميع إلى النهاية دائماً، أو داخل HAVING لاستخراج صفوف المجاميع الفرعية فقط.
-- Distinguish real NULLs (0) from ROLLUP subtotal rows (1)
SELECT dept_id,
job_role,
GROUPING(dept_id) AS is_grand_total,
GROUPING(job_role) AS is_dept_subtotal,
SUM(salary) AS total_salary
FROM employees
GROUP BY dept_id, job_role WITH ROLLUP;
من أهم المفاهيم الهندسية لإتقان SQL إدراك أن محرك قاعدة البيانات لا ينفّذ جمل الاستعلام بالترتيب الذي تُكتب به:
- الترتيب النحوي المكتوب: يبدأ بـ
SELECTثمFROMثمWHEREثمGROUP BYثمHAVINGثمORDER BYوأخيراًLIMIT. - الترتيب المنطقي للتنفيذ الفعلي: يبدأ بـ
1. FROM(تحديد الجدول) ←2. WHERE(تصفية الصفوف) ←3. GROUP BY(تجميع المجموعات) ←4. HAVING(تصفية المجموعات) ←5. SELECT(حساب الأعمدة والأسماء المستعارة) ←6. DISTINCT(إزالة التكرار) ←7. ORDER BY(الفرز) ←8. LIMIT / OFFSET(اقتطاع الصفحة).
يفسّر هذا التسلسل المنطقي ذو المراحل الثماني جميع القواعد السلوكية التي تعلّمتها في وحدتي التصفية والتجميع.
-- Every clause written in lexical order, executed 1..8 logically
SELECT DISTINCT category,
COUNT(*) AS item_cnt,
SUM(stock_qty) AS total_stock
FROM products
WHERE is_active = 1
GROUP BY category
HAVING COUNT(*) >= 2
ORDER BY total_stock DESC
LIMIT 5 OFFSET 0;
بما أن الأسماء المستعارة للأعمدة AS alias_name تُعرَّف في مرحلة SELECT (المرحلة الخامسة في التنفيذ المنطقي)، فإن صلاحية استخدامها في بقية جمل الاستعلام تخضع لقواعد واضحة:
- ممنوعة قطعياً في
WHERE(المرحلة 2): عند تنفيذWHEREلم تكن مرحلةSELECTقد بدأت بعد، لذا فإن استخدام الاسم المستعار داخلWHEREيُطلق دائماً الخطأError 1054: Unknown column. - مدعومة قياسياً في
ORDER BY(المرحلة 7): تعمل الأسماء المستعارة فيORDER BYفي جميع قواعد البيانات لأن الفرز يتم بعد اكتمالSELECT. - امتداد MySQL في
GROUP BYوHAVING: يدعم محرك MySQL كامتداد مريح التعرّف على الأسماء المستعارة داخلGROUP BYوHAVINGأيضاً.
معرفة هذه القاعدة تختصر وقت تشخيص أخطاء الأعمدة غير المعروفة في الاستعلامات التحليلية.
-- WHERE uses raw expression; GROUP BY, HAVING & ORDER BY use alias
SELECT (unit_price - discount_usd) AS net_price,
COUNT(*) AS item_count
FROM products
WHERE (unit_price - discount_usd) > 0
GROUP BY net_price
HAVING item_count >= 2
ORDER BY net_price DESC;
يلخّص الجدول التالي المراحل الثماني للتنفيذ المنطقي لاستعلام SELECT في MySQL 8 مرتبةً حسب تسلسل تنفيذها الفعلي داخل المحرك:
| ترتيب التنفيذ | جملة SQL | الوظيفة الأساسية للمرحلة | هل ترى أسماء SELECT المستعارة؟ |
|---|---|---|---|
1 | FROM | تحديد الجدول المصدر والأسماء المستعارة للجداول | لا |
2 | WHERE | تصفية الصفوف الفردية الخام قبل التجميع | لا (تُطلق خطأ 1054) |
3 | GROUP BY [WITH ROLLUP] | تقسيم المجموعات وتوليد المجاميع التراكمية | نعم (ميزة في MySQL) |
4 | HAVING | تصفية المجموعات بناءً على نتائج الدوال التجميعية | نعم (ميزة في MySQL) |
5 | SELECT | حساب التعابير والدوال وتعريف الأسماء المستعارة للأعمدة | تُعرَّف في هذه المرحلة |
6 | DISTINCT | إزالة الصفوف المتطابقة المكررة من النتيجة | نعم |
7 | ORDER BY | ترتيب الصفوف النهائية تصاعدياً أو تنازلياً | نعم (قياسي عالمياً) |
8 | LIMIT / OFFSET | اقتطاع شريحة الصفحة المطلوبة وإرسالها للعميل | تقبل أعداداً صحيحة |
ملخص الدرس: أتقنت في هذا الدرس توليد المجاميع الفرعية والعامة عبر WITH ROLLUP، وتمييز صفوف المجموع التراكمي بدالة GROUPING()، وفهم المسار المنطقي الكامل لتنفيذ استعلامات SQL من FROM حتى LIMIT.
الخطوة التالية والدرس القادم: ننتقل في الوحدة القادمة (الدوال المدمجة Built-In Functions) إلى معالجة النصوص والأرقام والتواريخ والتعابير الشرطية في MySQL 8.
-- Complete rollup report sorted with grand total last
SELECT dept_id,
GROUPING(dept_id) AS is_grand_total,
COUNT(*) AS staff_count,
SUM(salary) AS dept_payroll
FROM employees
WHERE is_active = 1
GROUP BY dept_id WITH ROLLUP
ORDER BY GROUPING(dept_id) ASC, dept_id ASC;
ملخص الدرس
حصاد الدرسمراجعة مركّزة لأهم المفاهيم والقواعد الهندسية التي أتقنتها في هذا الدرس قبل التطبيق العملي
ماذا تعلّمت في هذا الدرس؟
أتقنّا في هذا الدرس المجاميع الفرعية عبر ROLLUP والترتيب المنطقي لتنفيذ الاستعلام في MySQL 8 مع أمثلة عملية.
الخطوة التالية والدرس القادم
أكمل التدريبات والاختبار التفاعلي أدناه قبل الانتقال إلى الدرس التالي في مسار MySQL.
سجّل الدخول لحفظ تقدمك
تابع إنجاز المواضيع والمصطلحات والمهام، وكمّل من آخر خطوة على أي جهاز.
المصطلحات4
راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.
- 01 WITH ROLLUP معدِّل المجاميع الفرعية WITH ROLLUP
- إضافة لجملة GROUP BY تولّد تلقائياً صفوف المجاميع الفرعية وصف المجموع العام الكلي من اليمين إلى اليسار.
- للمراجعة
- 02 GROUPING() Function دالة تمييز التجميع GROUPING()
- دالة قياسية في MySQL 8 تُعيد 1 إذا كانت قيمة NULL ناتجة عن صف مجموع ROLLUP وتُعيد 0 للصفوف العادية.
- للمراجعة
- 03 Super-Aggregate Row صف التجميع الفائق (Super-Aggregate Row)
- صف إحصائي يولّده WITH ROLLUP لجمع نتائج المجموعات الفرعية وعرض المجموع الفرعي أو العام.
- للمراجعة
- 04 Logical Query Execution Order الترتيب المنطقي لتنفيذ الاستعلام
- التسلسل المنطقي الفعلي لتنفيذ مراحل الاستعلام بدءاً من FROM ثم WHERE ثم GROUP BY ثم HAVING ثم SELECT ثم ORDER BY و LIMIT.
- للمراجعة
لا توجد بطاقات تطابق البحث والتصفية.
اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.
الاختصارات4
راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.
- 01 OLAP OLAP
- Online Analytical Processing
- المعالجة التحليلية الفورية للبيانات التي تعتمد على المجاميع الهرمية مثل WITH ROLLUP
- للمراجعة
- 02 SQL SQL
- Structured Query Language
- لغة الاستعلامات البنيوية القياسية
- للمراجعة
- 03 ISO ISO
- International Organization for Standardization
- المنظمة الدولية للمعايير المعتمدة لدالة GROUPING() وترتيب تنفيذ الاستعلام
- للمراجعة
- 04 DBMS DBMS
- Database Management System
- نظام إدارة قواعد البيانات المسؤول عن تحليل وتنفيذ خطة الاستعلام
- للمراجعة
لا توجد بطاقات تطابق البحث والتصفية.
اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.
مهامك قبل الاختبار
خطوة صغيرة كل مرة. وإنجاز تقدر ترجع له.
-
اكتب استعلام SELECT على جدول products يعرض category و COUNT(*) باسم item_count و SUM(stock_qty) باسم total_stock مجمّعةً حسب category مع إضافة WITH ROLLUP.
-
اكتب استعلام SELECT على جدول orders يعرض payment_method و GROUPING(payment_method) باسم is_total و SUM(total_usd) باسم revenue مجمّعةً حسب payment_method WITH ROLLUP.
تأشير المهمة إقرار منك بإتمامها، وليس تصحيحًا آليًا للكود. يُحفظ تقدمك في حسابك.
اختبر فهمك.
ووصلها للإتقان.
كل سؤال خطوة لقدّام. اختار، اكتب كود، وشوف نتيجتك فورًا.
أكمل المهام، واجمع كل الإجابات الصحيحة. أقل من 100%؟ راجع وأعد المحاولة.
الأسئلة متاحة للاطلاع. سجّل الدخول للتفاعل وحفظ تقدمك.
لمحة عن التحدي8 أسئلة تنتظرك +
ماذا يضيف إلحاق العبارة WITH ROLLUP بجملة GROUP BY dept_id إلى نتائج الاستعلام؟
يولّد WITH ROLLUP صفاً إضافياً للمجموع العام ويضع القيمة NULL في عمود التجميع للدلالة على الشمول الكلي.
عند كتابة GROUP BY region, country WITH ROLLUP، ما مستويات التلخيص التي يولّدها المحرك؟
يُجمّع WITH ROLLUP الأعمدة من اليمين إلى اليسار؛ فيُصفّر العمود الأيمن country أولاً ثم العمودين معاً.
ماذا تُعيد الدالة GROUPING(dept_id) في صف المجموع الناتج عن ROLLUP مقارنةً بالصف العادي (حتى لو كانت قيمته في الجدول NULL)؟
صُمّمت دالة GROUPING(col) لتُعيد 1 فقط عندما تكون NULL ناتجة عن التجميع الفائق ROLLUP وتُعيد 0 للبيانات العادية.
ما الجملة التي تُنفَّذ أولاً في الترتيب المنطقي لتنفيذ استعلام SELECT في SQL؟
رغم أن SELECT تُكتب في بداية الاستعلام، يبدأ المحرك منطقياً بتنفيذ FROM لتحديد الجدول وقراءة بياناته.
ما الترتيب المنطقي الصحيح لتنفيذ المراحل الأربع: WHERE و GROUP BY و HAVING و SELECT؟
تُصفّى الصفوف أولاً بـ WHERE، ثم تُجمّع بـ GROUP BY، ثم تُصفّى المجموعات بـ HAVING، ثم تُعرض الأعمدة بـ SELECT.
لماذا يؤدي استخدام الاسم المستعار للعمود المعرّف في SELECT داخل جملة WHERE إلى الخطأ 1054؟
تُنفّذ WHERE في المرحلة الثانية بينما لا تُعرّف الأسماء المستعارة للأعمدة إلا عند الوصول للمرحلة الخامسة SELECT.
لماذا يصح استخدام الاسم المستعار للجدول (مثل FROM orders AS o) داخل جملة WHERE (مثل WHERE o.total > 100)؟
تُربط الأسماء المستعارة للجداول في المرحلة الأولى FROM، لذا تتعرف عليها جميع المراحل اللاحقة ومنها WHERE.
أي جملة تُنفَّذ في المرحلة الأخيرة تماماً (المرحلة 8) بعد اكتمال فرز النتائج بجملة ORDER BY؟
تُنفَّذ LIMIT و OFFSET في المرحلة الثامنة والأخيرة لاقتطاع عدد الصفوف المطلوب بعد اكتمال ترتيبها.