0Pricing
SQL Interview Prep · درس

قاعدة GROUP BY لأعمدة SELECT

سبب وجوب ظهور كل عمود غير مجمع في GROUP BY ووضع only-full-group-by

قاعدة GROUP BY لأعمدة SELECT درس مجاني في SQL Interview Prep على CoddyKit. هذا هو الدرس 1 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في SQL Interview Prep، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة SQL Interview Prep 4 دروس في المجموع.

لماذا يبدأ المقابلون بـ GROUP BY

يمثل GROUP BY المرحلة التي تميز المقابلات فيها بين المبتدئين والمطورين ذوي الخبرة المتوسطة. والقاعدة الوحيدة التي يختبرونها أكثر من غيرها هي: يجب أن يكون كل عمود في قائمة SELECT إما داخل دالة تجميعية أو مدرجًا في GROUP BY.

إذا خالفت هذه القاعدة، فلن يتمكن المحرك من تحديد القيمة التي يجب عرضها لمجموعة تضم صفوفًا متعددة. ويتعمد المقابلون طرح هذا الخطأ تحديدًا لمعرفة ما إذا كنت تفهم ماهية المجموعة فعلًا.

ماهيّة المجموعة فعليًا

يختزل GROUP BY صفوفًا متعددة إلى صف واحد لكل مفتاح مميز. بعد التجميع، لا يعود لدى المحرك صفوف فردية، بل لا يملك سوى صف تلخيص واحد لكل مجموعة.

  • للأعمدة التي جمّعت حسبها قيمة واضحة واحدة لكل مجموعة.
  • تختزل الدوال التجميعية مثل COUNT وSUM وAVG القيم المتعددة إلى قيمة واحدة.
  • أي عمود خام آخر يكون غامضًا: أي قيمة من القيم المتعددة ينبغي عرضها؟
SELECT department, COUNT(*) AS headcount
FROM employees
GROUP BY department;

الخطأ الشائع

إليك الخطأ الذي يحب المقابلون رؤيته. فأنت تجمع حسب department، لكنك تعرض أيضًا name، وهو عمود غير تجميعي وغير مدرج في GROUP BY.

يضم كل قسم عدة موظفين، ولذلك توجد أسماء متعددة في كل مجموعة. ولا يستطيع المحرك اختيار اسم واحد، لذا فإن SQL القياسي يرفض الاستعلام.

-- ERROR: name is not in GROUP BY and not aggregated
SELECT department, name, COUNT(*)
FROM employees
GROUP BY department;

طريقتان لإصلاحه

لديك إصلاحان مشروعان، ويريد المقابل أن يسمع منك أنك تعرف أن كلًا منهما ينتج إجابة مختلفة:

  • أضف العمود إلى GROUP BY إذا كنت تريد فعلًا تجميعًا أكثر تفصيلًا (صفًا واحدًا لكل قسم واسم).
  • ضعه داخل دالة تجميعية مثل MAX(name) أو COUNT(name) إذا كنت تريد قيمة واحدة لكل مجموعة موجودة.
-- Finer grouping
SELECT department, name, COUNT(*) AS rows_for_person
FROM employees
GROUP BY department, name;

ONLY_FULL_GROUP_BY في MySQL

هذا فخ مفضل لدى المقابلين: كان MySQL القديم يسمح بعرض أعمدة غير مجمعة، ويعيد بصمت قيمة عشوائية من المجموعة. وكان ذلك ينتج تقارير خاطئة تبدو سليمة.

يفعّل MySQL الحديث ONLY_FULL_GROUP_BY افتراضيًا، ما يفرض القاعدة القياسية. أما Postgres وSQL Server وOracle فقد فرضتها دائمًا. وإذا سُئلت عن سبب «عمل الاستعلام على الخادم القديم وتعطله الآن»، فهذه هي الإجابة.

-- Legal under ONLY_FULL_GROUP_BY because every
-- selected column is grouped or aggregated
SELECT department, MAX(hire_date) AS latest_hire
FROM employees
GROUP BY department;

استثناء الاعتماد الوظيفي

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

يسمح Postgres وMySQL الحديث بعرض تلك الأعمدة التابعة من دون إدراجها في قائمة التجميع. فالمفتاح المجمّع يحددها بشكل فريد، ولذلك لا يوجد أي غموض.

-- Legal: id is the PK, so name is determined by it
SELECT e.id, e.name, COUNT(o.id) AS orders
FROM employees e
LEFT JOIN orders o ON o.employee_id = e.id
GROUP BY e.id;

مثال تطبيقي: المبيعات حسب المنطقة

افترض أنك مطالب بإعداد تقرير بإجمالي المبيعات لكل منطقة. مفتاح التجميع هو region، والمقياس هو SUM(amount). ويجب تجميع كل ما عدا ذلك أو حذفه.

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

SELECT region,
       SUM(amount)   AS total_sales,
       COUNT(*)      AS num_orders,
       AVG(amount)   AS avg_order
FROM sales
GROUP BY region;

الخلط بين التفاصيل والملخص

إليك سؤالًا خادعًا: «اعرض قيمة كل طلب بجانب إجمالي منطقته». لا يمكنك فعل ذلك باستخدام GROUP BY العادي، لأن التجميع يلغي الصفوف الفردية.

الإجابة الصحيحة هي دالة نافذة (SUM(amount) OVER (PARTITION BY region)) أو إعادة الربط باستعلام فرعي مجمّع. وإدراك أن GROUP BY ليس الأداة المناسبة هنا هو جوهر السؤال.

-- Detail rows kept, region total added per row
SELECT order_id, region, amount,
       SUM(amount) OVER (PARTITION BY region) AS region_total
FROM sales;

GROUP BY والأسماء المستعارة في SELECT

هل يمكنك استخدام اسم مستعار مع GROUP BY إذا عرّفته في SELECT؟ يعتمد ذلك على لهجة SQL، وهذا الاختلاف هو تحديدًا ما يستكشفه المقابلون.

  • MySQL وPostgres: يسمحان بالتجميع حسب اسم مستعار في SELECT.
  • SQL Server وOracle: لا يسمحان بذلك؛ ويجب تكرار التعبير كاملًا.

الإجابة المتوافقة مع مختلف الأنظمة هي تكرار التعبير في GROUP BY، إذ يعمل ذلك في كل مكان.

-- Portable: repeat the expression rather than the alias
SELECT EXTRACT(YEAR FROM order_date) AS yr, COUNT(*)
FROM sales
GROUP BY EXTRACT(YEAR FROM order_date);

DISTINCT مقابل GROUP BY للتفرّد

إذا كنت تريد التركيبات المميزة فقط من دون أي تجميع، فإن GROUP BY من دون دالة تجميعية يتصرف مثل DISTINCT. وقد يسألك المقابلون أيهما أوضح.

استخدم DISTINCT للتعبير عن القصد («أريد صفوفًا فريدة»). واحتفظ بـ GROUP BY للحالات التي تحسب فيها أيضًا قيمًا تجميعية. النتيجة واحدة، لكن الإشارة التي تقدمها قابلية القراءة مختلفة.

-- These return the same rows
SELECT DISTINCT department, role FROM employees;
SELECT department, role FROM employees GROUP BY department, role;

كيف تشرح ذلك في المقابلة

عندما تواجه سؤالًا عن GROUP BY، اشرح القاعدة بصوت عالٍ: «كل عمود محدد إما مفتاح تجميع أو موضوع داخل دالة تجميعية، لأن التجميع يترك صفًا واحدًا لكل مفتاح».

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

تحقق سريع

اختبر مدى استيعابك للقاعدة الأساسية في GROUP BY.

خلاصة

القاعدة: يجب أن يكون كل عمود في SELECT مفتاح تجميع أو قيمة تجميعية. السبب: يترك GROUP BY صفًا واحدًا لكل مفتاح، ولذلك تكون الأعمدة الخام غير المجمعة غامضة.

  • أصلح المخالفات بتجميع العمود أو تطبيق دالة تجميعية عليه.
  • كان السلوك القديم في MySQL يعيد قيمًا عشوائية؛ وتفرض ONLY_FULL_GROUP_BY الالتزام بالمعيار.
  • التبعية الوظيفية للمفتاح الأساسي هي الاستثناء القانوني الوحيد.
  • للحفاظ على صفوف التفاصيل بجانب إجماليات المجموعات، استخدم دوال النوافذ بدلًا من GROUP BY.

الأسئلة الشائعة

هل درس «قاعدة GROUP BY لأعمدة SELECT» مجاني؟

نعم — نص درس «قاعدة GROUP BY لأعمدة SELECT» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة SQL Interview Prep، انتقل إلى CoddyKit PRO. تتضمن دورة SQL Interview Prep 4 دروس في المجموع.

ماذا ستتعلم في «قاعدة GROUP BY لأعمدة SELECT»؟

سبب وجوب ظهور كل عمود غير مجمع في GROUP BY ووضع only-full-group-by تتمرن على SQL Interview Prep مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ SQL Interview Prep؟

لا تُشترط خبرة سابقة. SQL Interview Prep على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 1 من أصل 4.

كم من الوقت يستغرق درس «قاعدة GROUP BY لأعمدة SELECT»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس SQL Interview Prep هذا؟

نعم. كل درس في SQL Interview Prep يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. قاعدة GROUP BY لأعمدة SELECT
  2. HAVING مقابل WHERE
  3. التجميع حسب عدة أعمدة وتعبيرات
  4. عد المجموعات وتصفيتها
← العودة إلى SQL Interview Prep