خانه/ تجمیع داده‌ها/ GROUP BY

GROUP BY: دسته‌بندی و خلاصه‌سازی داده

مبتدی ۱۴ دقیقه مطالعه

در سه درس قبل، COUNT، SUM و AVG کل جدول را در یک ردیف خلاصه کردند. اما سوال واقعی‌تر این است: «درآمد هر دسته چقدر است؟» یا «چند محصول از هر دسته داریم؟» — یعنی می‌خواهیم به‌جای یک خلاصه‌ی کلی، یک خلاصه برای هر گروه داشته باشیم. این دقیقاً کاری است که GROUP BY انجام می‌دهد.

ساختار پایه

sql
SELECT category, COUNT(*) AS ProductCount, SUM(price * quantity) AS Revenue
FROM sales
GROUP BY category;

این پرس‌وجو ردیف‌های sales را بر اساس category در دسته‌های جدا می‌ریزد، و برای هر دسته، یک ردیف خروجی با تعداد و مجموع درآمد آن دسته می‌سازد. بیا نتیجه را ببینیم:

امتحانش کن — خلاصه‌سازی بر اساس دسته

قانون طلایی GROUP BY

در SQL Server یک قانون سخت‌گیرانه وجود دارد: هر ستونی که در SELECT بیاوری و داخل یک تابع تجمیعی (COUNT, SUM, ...) نباشد، باید حتماً در GROUP BY هم باشد. برای مثال، این پرس‌وجو در SQL Server واقعی با خطا متوقف می‌شود:

sql
SELECT product, category, COUNT(*)
FROM sales
GROUP BY category;
-- خطا: ستون 'sales.product' نه در تابع تجمیعی است، نه در GROUP BY

دلیلش منطقی است: وقتی چند ردیف در یک گروه جمع می‌شوند، SQL Server نمی‌داند کدام product را نشان بدهد — هر گروه ممکن است چند محصول متفاوت داشته باشد. بیا همین پرس‌وجو را در Playground این سایت امتحان کنیم:

همین پرس‌وجو را این‌جا امتحان کن
نکته‌ی مهم: برخلاف SQL Server، این پرس‌وجو در SQLite بدون خطا اجرا می‌شود و برای هر گروه، فقط یکی از محصولات را (به‌طور تقریباً اتفاقی) نشان می‌دهد — نه لزوماً معنادار. این یکی دیگر از تفاوت‌های واقعی بین دو موتور است: کدی که این‌جا «کار می‌کند»، ممکن است در SQL Server واقعی با خطا متوقف شود. قانون امن همیشه یکی است: هر ستون غیرتجمیعی در SELECT را حتماً در GROUP BY هم بیاور، حتی اگر SQLite اجازه‌ی حذفش را بدهد.

GROUP BY روی چند ستون

می‌توان بیش از یک ستون را برای گروه‌بندی مشخص کرد؛ در این حالت، هر ترکیب یکتا از آن ستون‌ها یک گروه جداگانه می‌شود — دقیقاً همان مفهومی که در درس DISTINCT دیدیم:

sql
SELECT city, grade, COUNT(*) AS StudentCount
FROM students
GROUP BY city, grade;

بیا این را روی جدول students امتحان کنیم:

امتحانش کن — گروه‌بندی چندستونی

WHERE و GROUP BY با هم

WHERE پیش از گروه‌بندی، روی ردیف‌های خام اعمال می‌شود — یعنی می‌توانی قبل از خلاصه‌سازی، بخشی از داده را کنار بگذاری:

sql
SELECT category, SUM(price * quantity) AS Revenue
FROM sales
WHERE quantity IS NOT NULL
GROUP BY category;

جایگاه GROUP BY در ترتیب پردازش منطقی

تا الان چند بار به ترتیب پردازش منطقی اشاره کردیم؛ حالا با اضافه‌شدن GROUP BY، تصویر کامل‌تر می‌شود:

FROMWHEREGROUP BYHAVINGSELECTORDER BY. یعنی WHERE روی ردیف‌های خام کار می‌کند (قبل از گروه‌بندی)، در حالی که HAVING — که در درس بعدی می‌بینیم — روی نتیجه‌ی گروه‌بندی‌شده کار می‌کند.

جمع‌بندی این درس

  • GROUP BY ردیف‌ها را بر اساس یک یا چند ستون دسته‌بندی می‌کند و یک ردیف خلاصه به‌ازای هر گروه می‌سازد.
  • در SQL Server، هر ستون غیرتجمیعی در SELECT باید در GROUP BY هم باشد؛ SQLite این قانون را سخت‌گیرانه اجرا نمی‌کند.
  • GROUP BY روی چند ستون، یعنی گروه‌بندی بر اساس ترکیب یکتای آن‌ها.
  • WHERE پیش از گروه‌بندی اجرا می‌شود؛ فیلتر کردن خود گروه‌ها موضوع درس بعدی است.

در آخرین درس این فصل، سراغ HAVING می‌رویم: چطور گروه‌هایی را که خودشان شرط خاصی دارند (مثلاً «دسته‌هایی با بیش از ۲ محصول») فیلتر کنیم.