SQL’da GROUP BY, HAVING va agregat funksiyalar
Amaliyot3 daqInnovialabs tahririyati
Qisqacha
GROUP BY qatorlarni guruhlarga yig‘adi, agregat funksiyalar har bir guruh uchun bitta qiymat hisoblaydi, WHERE qatorlarni guruhlashdan oldin, HAVING esa tayyor guruhlarni filtrlaydi.
Qisqa javob
- GROUP BY bir xil qiymatli qatorlarni guruhlarga birlashtiradi.
- Agregat funksiyalar (
COUNT,SUM,AVG,MIN,MAX) har bir guruh uchun bitta qiymat qaytaradi. - WHERE qatorlarni guruhlashdan oldin olib tashlaydi.
- HAVING guruhlarni hisoblangandan keyin olib tashlaydi.
SELECT city, COUNT(*) AS orders, SUM(total) AS revenue
FROM orders
WHERE status = 'paid'
GROUP BY city
HAVING SUM(total) > 1000000
ORDER BY revenue DESC;
Bu shunday o‘qiladi: to‘langan buyurtmalarni olish, shahar bo‘yicha guruhlash, soni va tushumni hisoblash, tushumi milliondan oshgan shaharlarni qoldirish.
Savdo misolida beshta agregat funksiya
orders(id, customer_id, city, total, status, created_at) jadvali.
SELECT
COUNT(*) AS orders_count,
COUNT(DISTINCT customer_id) AS customers,
SUM(total) AS revenue,
AVG(total) AS avg_check,
MIN(total) AS min_order,
MAX(total) AS max_order
FROM orders
WHERE status = 'paid';
GROUP BYsiz butun tanlov bitta guruh hisoblanadi va umumiy raqamlar bilan bitta qator olasiz. GROUP BY city qo‘shsangiz, har bir shahar uchun shunday qator chiqadi.
Muhim jihatlar:
COUNT(*)barcha qatorlarni sanaydi,COUNT(column)esa faqat qiymati NULL bo‘lmagan qatorlarni.SUM,AVG,MIN,MAXNULL’ni hisobga olmaydi. Bo‘shliqlari bor ustun bo‘yichaAVGfaqat to‘ldirilgan qiymatlar o‘rtachasini hisoblaydi.- Bo‘sh to‘plam bo‘yicha
SUM0 emas,NULLqaytaradi.COALESCE(SUM(total), 0)ishlating.
WHERE yoki HAVING
| WHERE | HAVING | |
|---|---|---|
| Qachon ishlaydi | guruhlashdan oldin | guruhlashdan keyin |
| Nimani filtrlaydi | alohida qatorlar | guruhlar |
| Agregatlar mumkinmi | yo‘q | ha |
Qoida: agar shart alohida qatorga tegishli bo‘lsa (status, sana, shahar), uni WHEREga yozing — shunda baza kamroq ma’lumotni qayta ishlaydi. HAVINGda faqat agregatlar bo‘yicha shartlarni qoldiring.
-- 2026-yilda 3 va undan ko‘p to‘langan buyurtma qilgan mijozlar
SELECT customer_id, COUNT(*) AS orders
FROM orders
WHERE status = 'paid'
AND created_at >= '2026-01-01' AND created_at < '2027-01-01'
GROUP BY customer_id
HAVING COUNT(*) >= 3;
Sanalar bo‘yicha guruhlash
Oylik hisobot — eng ko‘p uchraydigan vazifa. Sanani davr boshiga keltirish kerak:
-- PostgreSQL
SELECT DATE_TRUNC('month', created_at) AS month, SUM(total) AS revenue
FROM orders
WHERE status = 'paid'
GROUP BY DATE_TRUNC('month', created_at)
ORDER BY month;
-- MySQL
SELECT DATE_FORMAT(created_at, '%Y-%m') AS month, SUM(total) AS revenue
FROM orders
WHERE status = 'paid'
GROUP BY DATE_FORMAT(created_at, '%Y-%m')
ORDER BY month;
E’tibor bering: qaysidir oyda savdo bo‘lmagan bo‘lsa, natijada u oy umuman chiqmaydi. Nollarni ko‘rsatish uchun natijani kalendar bilan LEFT JOIN orqali bog‘lang (PostgreSQL’da generate_series yoki alohida sanalar jadvali).
Vaqt mintaqasini ham kuzating: agar vaqtlar UTC’da saqlansa, Toshkent vaqti bilan 01:00 dagi buyurtma oldingi kunga tushib qolishi mumkin.
Ko‘p uchraydigan xatolar
- SELECT’dagi ustun GROUP BY’da yo‘q va agregatlanmagan. PostgreSQL xato beradi,
ONLY_FULL_GROUP_BYrejimisiz MySQL esa guruhdan tasodifiy qiymat qaytaradi. - WHERE’da agregat —
WHERE SUM(total) > 100ishlamaydi,HAVINGkerak. - JOIN’dan keyin ikki marta sanash. Buyurtmalarni pozitsiyalar bilan bog‘lasangiz, har bir buyurtma summasi undagi pozitsiyalar soncha takrorlanadi. Avval agregatlang, keyin bog‘lang yoki pozitsiyalar bo‘yicha
SUMhisoblang. - Butun sonli bo‘lish. PostgreSQL’da butun sonlar bo‘yicha
AVGkasr qaytaradi, lekin butun sonliSUM(a) / COUNT(*)kasr qismini tashlab yuborishi mumkin. - HAVING’da alias. MySQL
HAVING revenue > 100ga ruxsat beradi, PostgreSQL — yo‘q:SUM(total)ifodasini takrorlang.