Към съдържанието
wannacode

GROUP BY: отчет по групи

Накратко: GROUP BY събира редовете с еднаква стойност в група, за да сметне брой, сума или средна за всяка група поотделно.

Проблем

Таблото на склада

Складът иска табло: колко поръчки са нови, колко платени, колко изпратени. С COUNT(*) и WHERE status = 'new' ще ти трябват пет заявки, по една за всяко състояние. А ако утре се появи шесто състояние, отчетът няма да го покаже.

Трябва една заявка, която сама намира състоянията и брои всяко.

Идеята

GROUP BY

GROUP BY колона слага в една група редовете с еднаква стойност в колоната. Обобщаващата функция се смята за всяка група поотделно:

SQLбаза: магазин

60 поръчки, пет групи, пет реда. Всяка група дава един ред.

Клиентите по град:

SQLбаза: магазин

Борис е без град и е в отделна група с city = NULL. За GROUP BY, както и за DISTINCT, всички NULL-и са една група.

Как една група става един ред, се вижда на малко редове. Последните три поръчки са шест реда в order_items:

SQLбаза: магазин

SELECT order_id, COUNT(*) AS lines, ROUND(SUM(quantity * unit_price), 2) AS total
FROM order_items
WHERE order_id >= 58
GROUP BY order_id;
Стъпка по стъпка, с думи
  1. 6 реда от order_items: продуктите в поръчки 58, 59 и 60.
  2. GROUP BY order_id: всеки ред отива в групата на своя order_id.
  3. 3 различни order_id, 3 групи. Във всяка има по 2 реда.
  4. Групата на 58 става един ред: COUNT(*) е 2, а SUM(quantity * unit_price) е 1 × 1,20 + 4 × 1,90 = 8,80 €.
  5. Групата на 59: 2 реда, 3 × 2,50 + 2 × 3,20 = 13,90 €.
  6. Групата на 60: 2 реда, 2 × 1,20 + 4 × 2,90 = 14,00 €.
  7. 6 реда влязоха, 3 излязоха: по един за всяка група.

Заявката от сцената. ROUND(…, 2) закръгля сбора до цент:

SQLбаза: магазин

Пробвай

Поръчки на клиент

Колко поръчки е направил всеки клиент? Покажи customer_id и броя.

SQLбаза: магазин

Идеята

Стойността на всяка поръчка

В order_items поръчката е на няколко реда, по един за всеки продукт. Групата по order_id събира редовете на една поръчка:

SQLбаза: магазин

Сега всяка поръчка е един ред: колко продукта има и за колко пари е.

Групата може да е и по две колони. Тогава в една група са редовете, в които и двете стойности са еднакви. Поръчките на клиент 1 по състояние:

SQLбаза: магазин

Групата може да е и по изчислена стойност. strftime('%Y-%m', ordered_at) взима годината и месеца от датата, и поръчките се групират по месец:

SQLбаза: магазин

Виж го

Колоната, която не е в групата

Поръчките по клиент, а до тях и състоянието. Изглежда разумно:

SQLбаза: магазин
1. Заявката показа „8 | cancelled | 3“. Какво значи това?

Поръчките на клиент 8 показват какво става:

SQLбаза: магазин

Три поръчки, три различни състояния. Групата е един ред, а в него има място за една стойност. SQLite не казва нищо и взима състоянието от един от редовете. Кой, не е обещано.

Правилото: всяка колона в SELECT е или в GROUP BY, или в обобщение (COUNT, SUM, MIN…). PostgreSQL и SQL Server дават грешка за такава заявка, MySQL също, с настройките си по подразбиране от версия 5.7. SQLite я приема и показва нещо, което изглежда като отговор.

Ако искаш състоянията, групирай по двете колони: GROUP BY customer_id, status.

По-точно, за любопитните

SQLite има една записана в документацията особеност: ако в заявката има точно едно MIN или MAX, свободната колона идва от реда с най-малката или най-голямата стойност. SELECT customer_id, MAX(ordered_at), id FROM orders GROUP BY customer_id дава номера на последната поръчка. Това е само в SQLite. Другите бази го отказват, а в модула за подзаявките ще видим как се прави навсякъде.

Пробвай

Най-продаваните

Кои пет продукта са продадени в най-много бройки? Покажи product_id и бройките в колона sold, най-продаваният пръв.

SQLбаза: магазин

Упражнение

Две справки

1. Колко продукта и колко бройки на склад има във всяка категория?

Покажи category_id, броя на продуктите и сбора на наличността им.

SQLбаза: магазин

2. Счетоводството иска броя на поръчките за всеки месец от 2026 г., подредени по месец.

Покажи месеца (година-месец) и броя на поръчките за всеки месец от 2026 г., по ред на месеците.

SQLбаза: магазин

Тест

Провери се

1. Колко реда връща SELECT status, COUNT(*) FROM orders GROUP BY status?
2. Борис е без град. Къде е той в SELECT city, COUNT(*) FROM customers GROUP BY city?
3. Какво дава GROUP BY customer_id, status?
4. Кое е безопасно в SELECT на заявка с GROUP BY order_id?

Създаден от Иво Гергов като част от кампанията на Evo Tech за достъпно обучение по програмиране ·