Window functions
Agar talaba SQL dan bitta ilg'or mavzuni o'rgansa, o'sha shu bo'lsin. Window function lar database dan so'rov qila oladigan odamni database ni tahlil qila oladigan odamdan ajratib turadi — running total, ranking, oydan-oyga o'zgarish, "har bir kategoriyada top 3" — va ular deyarli har bir jiddiy data analytics intervyusida uchraydi.
Mavjudligi: SQLite 3.25+ (2018), PostgreSQL, MySQL 8.0+, SQL Server 2012+. Barcha zamonaviy versiyalar qo'llab-quvvatlaydi.
Ular hal qiladigan muammo
GROUP BY ning bitta qattiq cheklovi bor: u row laringizni yo'q qiladi. Course bo'yicha guruhlaganingizdan keyin alohida enrollment lar yo'qoladi. Lekin real savollarning ko'pi ikkalasini birdan talab qiladi:
- "Har bir enrollment ni va uning course o'rtachasiga nisbatan holatini ko'rsat."
- "Har bir course ichida student larni reyting bo'yicha joylashtir."
- "Har bir oyning yig'indisini va shu paytgacha to'plangan umumiy yig'indini ko'rsat."
Window function joriy row bilan bog'liq row lar to'plami ustida, joriy row ni saqlab qolgan holda aggregate hisoblaydi.
OVER() clause
Har qanday aggregate OVER (...) qo'shilgan zahoti window function ga aylanadi. Bo'sh qavs "window — natijadagi barcha row lar" degani.
SELECT enrollment_id, grade, ROUND(AVG(grade) OVER (), 1) AS overall_avg, grade - AVG(grade) OVER () AS diff, COUNT(*) OVER () AS total_rows FROM enrollments WHERE grade IS NOT NULL ORDER BY grade DESC LIMIT 4;
| enrollment_id | grade | overall_avg | diff | total_rows |
|---|---|---|---|---|
| 135 | 100 | 73 | 27.024 | 1 826 |
| 322 | 100 | 73 | 27.024 | 1 826 |
| 500 | 100 | 73 | 27.024 | 1 826 |
| 699 | 100 | 73 | 27.024 | 1 826 |
4 qator
1 ms
enrollment_idgradeoverall_avgdifftotal_rows
1310079.4+20.5714 69579.4+15.5714 19279.4+12.5714 149179.4+11.5714
O'n to'rtta row saqlandi, ustiga har biriga xulosa column i qo'shildi. Umumiy shakli:
PARTITION BY
PARTITION BY — "siqmaydigan GROUP BY". Function har bir partition uchun qaytadan boshlanadi.
SELECT e.enrollment_id, e.course_id, e.grade, ROUND(AVG(e.grade) OVER (PARTITION BY e.course_id), 1) AS course_avg, e.grade - AVG(e.grade) OVER (PARTITION BY e.course_id) AS vs_course FROM enrollments e WHERE e.grade IS NOT NULL AND e.course_id IN (1, 2) ORDER BY e.course_id, e.grade DESC;
| enrollment_id | course_id | grade | course_avg | vs_course |
|---|---|---|---|---|
| 2 128 | 1 | 100 | 79.2 | 20.848 |
| 2 377 | 1 | 100 | 79.2 | 20.848 |
| 483 | 1 | 99 | 79.2 | 19.848 |
| 1 459 | 1 | 99 | 79.2 | 19.848 |
| 142 | 1 | 98 | 79.2 | 18.848 |
| 1 289 | 1 | 98 | 79.2 | 18.848 |
| 321 | 1 | 96 | 79.2 | 16.848 |
| 1 695 | 1 | 96 | 79.2 | 16.848 |
| 96 | 1 | 95 | 79.2 | 15.848 |
| 210 | 1 | 95 | 79.2 | 15.848 |
| 194 | 1 | 93 | 79.2 | 13.848 |
| 2 495 | 1 | 93 | 79.2 | 13.848 |
| 1 769 | 1 | 92 | 79.2 | 12.848 |
| 369 | 1 | 91 | 79.2 | 11.848 |
| 1 038 | 1 | 91 | 79.2 | 11.848 |
… 278 qatordan birinchi 15 tasi
278 qator
1 ms
enrollment_idcourse_idgradecourse_avgvs_course
119268.0+24.0 417568.0+7.0 915868.0−10.0 1514768.0−21.0 13210087.2+12.8 629587.2+7.8 228887.2+0.8 1728387.2−4.2 1027087.2−17.2
Har bir enrollment ko'rinib turibdi va har biri o'z course ining o'rtachasini olib yuribdi. Buni GROUP BY bilan qilish uchun o'rtachalarni alohida hisoblab, keyin qaytadan join qilish kerak bo'lardi — bitta clause o'rniga ikkita query.
ROW_NUMBER, RANK, DENSE_RANK
Uchta ranking function faqat tenglikni qanday hal qilishi bilan farq qiladi. Bizning course lardagi enrollment sanoqlarida haqiqiy tenglik bor (1 va 2-course da 5 tadan), bu farqni ko'rinadigan qiladi:
WITH per_course AS ( SELECT course_id, COUNT(*) AS n FROM enrollments GROUP BY course_id ) SELECT course_id, n, ROW_NUMBER() OVER (ORDER BY n DESC) AS row_number, RANK() OVER (ORDER BY n DESC) AS rank, DENSE_RANK() OVER (ORDER BY n DESC) AS dense_rank FROM per_course;
| course_id | n | row_number | rank | dense_rank |
|---|---|---|---|---|
| 11 | 200 | 1 | 1 | 1 |
| 1 | 193 | 2 | 2 | 2 |
| 14 | 189 | 3 | 3 | 3 |
| 15 | 188 | 4 | 4 | 4 |
| 13 | 187 | 5 | 5 | 5 |
| 2 | 186 | 6 | 6 | 6 |
| 10 | 179 | 7 | 7 | 7 |
| 3 | 174 | 8 | 8 | 8 |
| 6 | 174 | 9 | 8 | 8 |
| 8 | 170 | 10 | 10 | 9 |
| 4 | 167 | 11 | 11 | 10 |
| 5 | 167 | 12 | 11 | 10 |
| 7 | 165 | 13 | 13 | 11 |
| 9 | 161 | 14 | 14 | 12 |
14 qator
1 ms
course_idnROW_NUMBERRANKDENSE_RANK
15111 25211 54332 33443 43543
FunctionTeng qiymatlarKeyinQachon ishlatiladi
ROW_NUMBER()Har xil raqam oladi (tartib tasodifiy)Takrorlamaydi, o'tkazib yubormaydiGuruhdan aynan bitta row kerak bo'lganda
RANK()Bir xil raqam oladiKeyingi qiymatlarni o'tkazib yuboradi (1,1,3)Sport uslubidagi reyting: ikkita oltin, kumush yo'q
DENSE_RANK()Bir xil raqam oladiBo'shliq qoldirmaydi (1,1,2)"Bu qaysi darajaga tegishli?"
:::gotcha ⚠️ Tenglikda ROW_NUMBER noaniq
1 va 2-course da 5 tadan enrollment bor, shuning uchun qaysi biri 1-raqamni olishi engine ga bog'liq va har safar o'zgarishi mumkin. Tartib barqaror bo'lishi kerak bo'lsa, ajratuvchi qo'shing: ORDER BY n DESC, course_id ASC. ROW_NUMBER() qaysi row qolishini hal qiladigan har qanday holatda beqaror saralash natijangizni takrorlanmaydigan qiladi.
:::
Guruh bo'yicha Top-N
"Har bir course dagi eng yaxshi student", "har bir mijozning eng qimmat 3 ta buyurtmasi" — bu eng klassik window-function intervyu savoli, va uni window function siz toza qilishning iloji yo'q.
Pattern doim ikki qadam: har bir partition ichida row larni raqamlang, keyin kerakli raqamlarni qoldiring.
WITH ranked AS ( SELECT e.course_id, s.first_name, e.grade, ROW_NUMBER() OVER ( PARTITION BY e.course_id ORDER BY e.grade DESC ) AS rn FROM enrollments e JOIN students s ON s.student_id = e.student_id WHERE e.grade IS NOT NULL ) SELECT c.title, r.first_name, r.grade FROM ranked r JOIN courses c ON c.course_id = r.course_id WHERE r.rn = 1 -- top-3 uchun rn <= 3 qiling ORDER BY r.grade DESC;
| title | first_name | grade |
|---|---|---|
| Python Basics | Gulnora | 100 |
| Data Visualization | Kamola | 100 |
| Excel for Business | Nilufar | 100 |
| Project Management | Otabek | 100 |
| Graphic Design | Rustam | 100 |
| Financial Analysis | Madina | 100 |
| UX Design | Rustam | 97 |
| Java Basics | Nilufar | 97 |
| SQL for Analytics | Gulnora | 96 |
| Machine Learning | Bekzod | 94 |
| Web Development | Rustam | 94 |
| Linear Algebra | Jasur | 92 |
| Probability | Rustam | 91 |
| Statistics 101 | Aziza | 86 |
14 qator
2 ms
:::gotcha ⚠️ Nega bu yerda CTE majburiy
WHERE ROW_NUMBER() OVER (...) = 1 deb yozib bo'lmaydi. Window function lar SELECT qadamida hisoblanadi, u esa WHERE dan keyin (1-bobdagi bajarilish tartibi). WHERE ishlaganda window function hali mavjud emas. Uni CTE yoki derived table da hisoblang, keyin tashqi query da filtrlang. Talabalar bu xatoga doim duch keladi, va bajarilish tartibi diagrammasi buning tushuntirishi.
:::
Ikkita student eng yaxshi baho bo'yicha teng chiqsa, ROW_NUMBER ulardan aynan bittasini (tasodifiy) qaytaradi, RANK esa ikkalasini ham qaytaradi. Ikkalasi ham "to'g'ri" emas — biznes bitta g'olib istaydimi yoki barcha teng g'oliblarnimi, shunga bog'liq. So'rang, keyin ongli tanlang.
LAG va LEAD
LAG(col, n) n row orqaga, LEAD(col, n) n row oldinga qaraydi. Ikkalasining standart qiymati 1. Vaqt bo'yicha o'zgarishni shunday hisoblaysiz — va bu window function lar paydo bo'lishidan oldin ishlatilgan noqulay self-join ning o'rnini bosadi.
WITH monthly AS ( SELECT strftime('%Y-%m', enrolled_at) AS month, COUNT(*) AS n FROM enrollments GROUP BY month ) SELECT month, n, LAG(n) OVER (ORDER BY month) AS prev_month, n - LAG(n) OVER (ORDER BY month) AS change, ROUND(100.0 * (n - LAG(n) OVER (ORDER BY month)) / LAG(n) OVER (ORDER BY month), 1) AS pct_change FROM monthly ORDER BY month;
| month | n | prev_month | change | pct_change |
|---|---|---|---|---|
| 2025-02 | 1 077 | NaN | NaN | NaN |
| 2025-03 | 131 | 1 077 | -946 | -87.8 |
| 2025-09 | 1 188 | 131 | 1 057 | 806.9 |
| 2025-10 | 104 | 1 188 | -1 084 | -91.2 |
4 qator
1 ms
monthnprev_monthchangepct_change
2025-096NULLNULLNULL 2026-02126+6+100.0 2026-09212−10−83.3
Birinchi row NULL, chunki oldingi oy yo'q — bu xato emas, to'g'ri xatti-harakat. Raqam kerak bo'lsa standart qiymat bering: LAG(n, 1, 0).
LAG bitta row orqaga qadam tashlaydi, bitta oy emas. Enrollment i nol bo'lgan oylar row hosil qilmagani uchun 2026-02 ning "oldingi oyi" — 2025-yil sentyabri, ya'ni besh oy oldin. Aynan shuning uchun 6-bobdagi yaratilgan sana qatori muhim: avval to'liq qatorni quring, keyin uning ustidan LAG qiling. Buni noto'g'ri qilish oydan-oyga hisobotni indamay bema'ni hisobotga aylantiradi.
Running total va frame lar
OVER() ichiga ORDER BY qo'shish ma'noni tubdan o'zgartiradi: window "barcha row lar" o'rniga "boshidan joriy row gacha bo'lgan row lar" bo'lib qoladi. Bu — running total.
WITH monthly AS ( SELECT strftime('%Y-%m', enrolled_at) AS month, COUNT(*) AS n FROM enrollments GROUP BY month ) SELECT month, n, SUM(n) OVER (ORDER BY month) AS running_total, SUM(n) OVER () AS grand_total, ROUND(100.0 * SUM(n) OVER (ORDER BY month) / SUM(n) OVER (), 1) AS pct_of_total FROM monthly ORDER BY month;
| month | n | running_total | grand_total | pct_of_total |
|---|---|---|---|---|
| 2025-02 | 1 077 | 1 077 | 2 500 | 43.1 |
| 2025-03 | 131 | 1 208 | 2 500 | 48.3 |
| 2025-09 | 1 188 | 2 396 | 2 500 | 95.8 |
| 2025-10 | 104 | 2 500 | 2 500 | 100 |
4 qator
1 ms
monthnrunning_totalgrand_totalpct_of_total
2025-09662030.0 2026-0212182090.0 2026-0922020100.0
Bitta va o'sha function — SUM(n) — ORDER BY bilan running total, ORDER BY siz umumiy yig'indi beradi. Ikkalasi bitta query da.
Frame lar
Frame window qaysi row larni qamrashini aniq belgilaydi. ORDER BY yozib, frame yozmasangiz, standart quyidagicha bo'ladi:
| Frame | Nimani qamraydi |
|---|---|
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW |
Boshidan shu yergacha (running total) |
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW |
Oxirgi 3 ta row (moving average) |
ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING |
Ikkala tomondagi qo'shnilar (silliqlash) |
ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING |
Shu yerdan oxirigacha (qolgan yig'indi) |
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING |
Hammasi (ORDER BY siz bilan bir xil) |
ROWS jismoniy row larni sanaydi. RANGE esa ORDER BY qiymati bir xil bo'lgan row larni bitta qadam qilib biriktiradi. Sanalar takrorlansa, RANGE o'sha sanadagi barcha row larni qamraydi, ROWS esa kun o'rtasida to'xtaydi — ya'ni ROWS bilan qurilgan "kunlik running total" kunni ikkiga bo'lib yuborishi mumkin. Belgilangan sondagi row bo'ylab siljiydigan window uchun ROWS, guruhni ORDER BY qiymati belgilaganda esa RANGE ni afzal ko'ring.
Moving average
Moving (rolling) average shovqinli qatorni silliqlaydi. Quyida u bitta course ning baholari ustida, yozilish tartibida:
SELECT e.enrolled_at, e.grade, ROUND(AVG(e.grade) OVER ( ORDER BY e.enrolled_at ROWS BETWEEN 2 PRECEDING AND CURRENT ROW ), 2) AS moving_avg_3 FROM enrollments e WHERE e.course_id = 2 AND e.grade IS NOT NULL ORDER BY e.enrolled_at;
| enrolled_at | grade | moving_avg_3 |
|---|---|---|
| 2025-02-03 | 85 | 85 |
| 2025-02-04 | 83 | 84 |
| 2025-02-05 | 72 | 80 |
| 2025-02-05 | 67 | 74 |
| 2025-02-05 | 90 | 76.33 |
| 2025-02-06 | 80 | 79 |
| 2025-02-08 | 94 | 88 |
| 2025-02-08 | 89 | 87.67 |
| 2025-02-08 | 73 | 85.33 |
| 2025-02-08 | 77 | 79.67 |
| 2025-02-08 | 75 | 75 |
| 2025-02-08 | 76 | 76 |
| 2025-02-09 | 73 | 74.67 |
| 2025-02-09 | 90 | 79.67 |
| 2025-02-10 | 69 | 77.33 |
… 146 qatordan birinchi 15 tasi
146 qator
1 ms
enrolled_atgrademoving_avg_3
2025-09-058888.00 2025-09-189591.50 2026-02-047084.33 2026-02-0810088.33 2026-02-148384.33
Birinchi ikkita row uchtadan kam qiymat ustida o'rtacha oladi, chunki hali uchta row yo'q — window chekkalarda NULL qaytarmay, shunchaki qisqaradi. Hisobot faqat to'liq window larni ko'rsatishi kerak bo'lsa, COUNT(*) OVER (o'sha frame) = 3 bo'yicha filtrlang.
NTILE va PERCENT_RANK
NTILE(n) tartiblangan row larni n ta taxminan teng chelakka bo'ladi — kvartil, detsil, mijoz segmentlari.
SELECT enrollment_id, grade, NTILE(4) OVER (ORDER BY grade DESC) AS quartile, ROUND(PERCENT_RANK() OVER (ORDER BY grade DESC), 2) AS pct_rank FROM enrollments WHERE grade IS NOT NULL ORDER BY grade DESC;
| enrollment_id | grade | quartile | pct_rank |
|---|---|---|---|
| 135 | 100 | 1 | 0 |
| 322 | 100 | 1 | 0 |
| 500 | 100 | 1 | 0 |
| 699 | 100 | 1 | 0 |
| 814 | 100 | 1 | 0 |
| 1 096 | 100 | 1 | 0 |
| 1 202 | 100 | 1 | 0 |
| 1 832 | 100 | 1 | 0 |
| 1 862 | 100 | 1 | 0 |
| 2 126 | 100 | 1 | 0 |
| 2 128 | 100 | 1 | 0 |
| 2 161 | 100 | 1 | 0 |
| 2 377 | 100 | 1 | 0 |
| 2 424 | 100 | 1 | 0 |
| 483 | 99 | 1 | 0.01 |
… 1826 qatordan birinchi 15 tasi
1826 qator
3 ms
NTILE — mijozlarni segmentlash usuli. RFM tahlilida mijozlar recency, frequency va monetary value bo'yicha NTILE(5) yordamida 1–5 ballanadi, keyin uchta ball birlashtiriladi. Bu — sof SQL da bajariladigan eng ko'p uchraydigan real analytics vazifalaridan biri.
Window va GROUP BY
GROUP BY |
Window function | |
|---|---|---|
| Chiqish row lari | Har bir guruhga bitta | Kirish row lari bilan bir xil |
| Tafsilot row lari | Yo'qoladi | Saqlanadi |
| Qo'shni row larni ko'radimi | Yo'q | Ha (LAG, LEAD, frame lar) |
| Natijani nima bilan filtrlanadi | HAVING |
CTE + WHERE |
| Ranking | Imkonsiz | ROW_NUMBER, RANK |
| Qaysi qadamda ishlaydi | 3 | 5 (SELECT bilan) |
Ular yaxshi birlashadi — window function bitta query ichida GROUP BY natijasi ustida ishlashi mumkin:
SELECT course_id, COUNT(*) AS enrollments, SUM(COUNT(*)) OVER () AS total_enrollments, ROUND(100.0 * COUNT(*) / SUM(COUNT(*)) OVER (), 1) AS pct_of_all, RANK() OVER (ORDER BY COUNT(*) DESC) AS popularity_rank FROM enrollments GROUP BY course_id ORDER BY enrollments DESC;
| course_id | enrollments | total_enrollments | pct_of_all | popularity_rank |
|---|---|---|---|---|
| 11 | 200 | 2 500 | 8 | 1 |
| 1 | 193 | 2 500 | 7.7 | 2 |
| 14 | 189 | 2 500 | 7.6 | 3 |
| 15 | 188 | 2 500 | 7.5 | 4 |
| 13 | 187 | 2 500 | 7.5 | 5 |
| 2 | 186 | 2 500 | 7.4 | 6 |
| 10 | 179 | 2 500 | 7.2 | 7 |
| 6 | 174 | 2 500 | 7 | 8 |
| 3 | 174 | 2 500 | 7 | 8 |
| 8 | 170 | 2 500 | 6.8 | 10 |
| 5 | 167 | 2 500 | 6.7 | 11 |
| 4 | 167 | 2 500 | 6.7 | 11 |
| 7 | 165 | 2 500 | 6.6 | 13 |
| 9 | 161 | 2 500 | 6.4 | 14 |
14 qator
1 ms
course_idenrollmentstotal_enrollmentspct_of_allpopularity_rank
152025.01 252025.01 542020.03 332015.04 432015.04
SUM(COUNT(*)) OVER () g'alati ko'rinadi, lekin bajarilish tartibidan to'g'ridan-to'g'ri kelib chiqadi: COUNT(*) guruhlash qadamida hisoblanadi, window function esa keyin o'sha guruhlangan row lar ustida ishlaydi. "Har bir row ning umumiy natijadagi ulushi" — eng ko'p so'raladigan hisobot column laridan biri, va uni bitta query da olish yo'li aynan shu.
Mashqlar to'plami
-- 1. Har bir enrollment, uning course o'rtachasi va farqi SELECT enrollment_id, course_id, grade, ROUND(AVG(grade) OVER (PARTITION BY course_id), 1) AS course_avg FROM enrollments WHERE grade IS NOT NULL ORDER BY course_id, grade DESC; -- 2. Student larni umumiy o'rtacha baho bo'yicha reyting WITH avg_per_student AS ( SELECT student_id, AVG(grade) AS avg_grade FROM enrollments WHERE grade IS NOT NULL GROUP BY student_id ) SELECT s.first_name, ROUND(a.avg_grade,1) AS avg_grade, RANK() OVER (ORDER BY a.avg_grade DESC) AS rank FROM avg_per_student a JOIN students s USING (student_id); -- 3. Har bir course dagi eng yuqori baho (guruh bo'yicha top-1) WITH r AS ( SELECT course_id, student_id, grade, ROW_NUMBER() OVER (PARTITION BY course_id ORDER BY grade DESC) AS rn FROM enrollments WHERE grade IS NOT NULL ) SELECT * FROM r WHERE rn = 1; -- 4. Har bir student ning enrollment lari sana tartibida raqamlangan SELECT student_id, enrolled_at, course_id, ROW_NUMBER() OVER (PARTITION BY student_id ORDER BY enrolled_at) AS nth_course FROM enrollments ORDER BY student_id, enrolled_at; -- 5. Student ning ketma-ket enrollment lari orasidagi kunlar SELECT student_id, enrolled_at, LAG(enrolled_at) OVER (PARTITION BY student_id ORDER BY enrolled_at) AS prev, JULIANDAY(enrolled_at) - JULIANDAY(LAG(enrolled_at) OVER (PARTITION BY student_id ORDER BY enrolled_at)) AS days_gap FROM enrollments ORDER BY student_id, enrolled_at; -- 6. Vaqt bo'yicha enrollment larning running total i SELECT enrolled_at, COUNT(*) AS n, SUM(COUNT(*)) OVER (ORDER BY enrolled_at) AS running_total FROM enrollments GROUP BY enrolled_at ORDER BY enrolled_at; -- 7. Baholarni kvartillarga bo'lish SELECT enrollment_id, grade, NTILE(4) OVER (ORDER BY grade DESC) AS quartile FROM enrollments WHERE grade IS NOT NULL; -- 8. Har bir course ning umumiy daromaddagi ulushi SELECT c.title, SUM(c.price) AS revenue, ROUND(100.0 * SUM(c.price) / SUM(SUM(c.price)) OVER (), 1) AS pct FROM enrollments e JOIN courses c USING (course_id) GROUP BY c.course_id, c.title ORDER BY revenue DESC;
1-natija
| enrollment_id | course_id | grade | course_avg |
|---|---|---|---|
| 2 128 | 1 | 100 | 79.2 |
| 2 377 | 1 | 100 | 79.2 |
| 483 | 1 | 99 | 79.2 |
| 1 459 | 1 | 99 | 79.2 |
| 142 | 1 | 98 | 79.2 |
| 1 289 | 1 | 98 | 79.2 |
| 321 | 1 | 96 | 79.2 |
| 1 695 | 1 | 96 | 79.2 |
| 96 | 1 | 95 | 79.2 |
| 210 | 1 | 95 | 79.2 |
| 194 | 1 | 93 | 79.2 |
| 2 495 | 1 | 93 | 79.2 |
| 1 769 | 1 | 92 | 79.2 |
| 369 | 1 | 91 | 79.2 |
| 1 038 | 1 | 91 | 79.2 |
… 1826 qatordan birinchi 15 tasi
1826 qator
2-natija
| first_name | avg_grade | rank |
|---|---|---|
| Otabek | 87.3 | 1 |
| Shahnoza | 86.3 | 2 |
| Akmal | 84 | 3 |
| Zulfiya | 84 | 3 |
| Bekzod | 82.8 | 5 |
| Aziz | 82.5 | 6 |
| Shahnoza | 82.3 | 7 |
| Doston | 82.2 | 8 |
| Rustam | 81.8 | 9 |
| Gulnora | 81.6 | 10 |
| Ulug'bek | 81 | 11 |
| Nilufar | 81 | 11 |
| Aziz | 80.8 | 13 |
| Malika | 80.8 | 14 |
| Bekzod | 80.3 | 15 |
… 300 qatordan birinchi 15 tasi
300 qator
3-natija
| course_id | student_id | grade | rn |
|---|---|---|---|
| 1 | 24 | 100 | 1 |
| 2 | 24 | 96 | 1 |
| 3 | 232 | 86 | 1 |
| 4 | 129 | 100 | 1 |
| 5 | 136 | 94 | 1 |
| 6 | 206 | 94 | 1 |
| 7 | 247 | 100 | 1 |
| 8 | 197 | 100 | 1 |
| 9 | 195 | 97 | 1 |
| 10 | 41 | 100 | 1 |
| 11 | 202 | 92 | 1 |
| 13 | 222 | 97 | 1 |
| 14 | 178 | 100 | 1 |
| 15 | 206 | 91 | 1 |
14 qator
4-natija
| student_id | enrolled_at | course_id | nth_course |
|---|---|---|---|
| 1 | 2025-09-06 | 8 | 1 |
| 1 | 2025-09-07 | 13 | 2 |
| 1 | 2025-09-09 | 3 | 3 |
| 1 | 2025-09-13 | 11 | 4 |
| 1 | 2025-09-13 | 3 | 5 |
| 1 | 2025-09-17 | 11 | 6 |
| 1 | 2025-09-26 | 10 | 7 |
| 2 | 2025-02-13 | 2 | 1 |
| 2 | 2025-02-14 | 10 | 2 |
| 2 | 2025-02-15 | 13 | 3 |
| 2 | 2025-02-19 | 11 | 4 |
| 2 | 2025-02-25 | 3 | 5 |
| 2 | 2025-02-27 | 6 | 6 |
| 2 | 2025-03-02 | 7 | 7 |
| 2 | 2025-03-09 | 11 | 8 |
… 2500 qatordan birinchi 15 tasi
2500 qator
5-natija
| student_id | enrolled_at | prev | days_gap |
|---|---|---|---|
| 1 | 2025-09-06 | None | NaN |
| 1 | 2025-09-07 | 2025-09-06 | 1 |
| 1 | 2025-09-09 | 2025-09-07 | 2 |
| 1 | 2025-09-13 | 2025-09-09 | 4 |
| 1 | 2025-09-13 | 2025-09-13 | 0 |
| 1 | 2025-09-17 | 2025-09-13 | 4 |
| 1 | 2025-09-26 | 2025-09-17 | 9 |
| 2 | 2025-02-13 | None | NaN |
| 2 | 2025-02-14 | 2025-02-13 | 1 |
| 2 | 2025-02-15 | 2025-02-14 | 1 |
| 2 | 2025-02-19 | 2025-02-15 | 4 |
| 2 | 2025-02-25 | 2025-02-19 | 6 |
| 2 | 2025-02-27 | 2025-02-25 | 2 |
| 2 | 2025-03-02 | 2025-02-27 | 3 |
| 2 | 2025-03-09 | 2025-03-02 | 7 |
… 2500 qatordan birinchi 15 tasi
2500 qator
6-natija
| enrolled_at | n | running_total |
|---|---|---|
| 2025-02-03 | 6 | 6 |
| 2025-02-04 | 19 | 25 |
| 2025-02-05 | 35 | 60 |
| 2025-02-06 | 30 | 90 |
| 2025-02-07 | 42 | 132 |
| 2025-02-08 | 56 | 188 |
| 2025-02-09 | 58 | 246 |
| 2025-02-10 | 51 | 297 |
| 2025-02-11 | 55 | 352 |
| 2025-02-12 | 60 | 412 |
| 2025-02-13 | 64 | 476 |
| 2025-02-14 | 59 | 535 |
| 2025-02-15 | 55 | 590 |
| 2025-02-16 | 53 | 643 |
| 2025-02-17 | 51 | 694 |
… 94 qatordan birinchi 15 tasi
94 qator
7-natija
| enrollment_id | grade | quartile |
|---|---|---|
| 135 | 100 | 1 |
| 322 | 100 | 1 |
| 500 | 100 | 1 |
| 699 | 100 | 1 |
| 814 | 100 | 1 |
| 1 096 | 100 | 1 |
| 1 202 | 100 | 1 |
| 1 832 | 100 | 1 |
| 1 862 | 100 | 1 |
| 2 126 | 100 | 1 |
| 2 128 | 100 | 1 |
| 2 161 | 100 | 1 |
| 2 377 | 100 | 1 |
| 2 424 | 100 | 1 |
| 483 | 99 | 1 |
… 1826 qatordan birinchi 15 tasi
1826 qator
8-natija
| title | revenue | pct |
|---|---|---|
| Financial Analysis | 283 500 000 | 9.8 |
| Project Management | 255 000 000 | 8.8 |
| Machine Learning | 242 150 000 | 8.4 |
| Linear Algebra | 240 000 000 | 8.3 |
| Probability | 235 000 000 | 8.1 |
| Python Basics | 231 600 000 | 8 |
| Java Basics | 215 050 000 | 7.4 |
| Statistics 101 | 208 800 000 | 7.2 |
| Web Development | 200 100 000 | 6.9 |
| Excel for Business | 181 500 000 | 6.3 |
| Graphic Design | 170 050 000 | 5.9 |
| Data Visualization | 150 300 000 | 5.2 |
| SQL for Analytics | 148 800 000 | 5.1 |
| UX Design | 136 850 000 | 4.7 |
14 qator
16 ms
Intervyu savollari
S: Window function nima va u aggregate dan nimasi bilan farq qiladi?
Ikkalasi ham row lar to'plami ustida hisoblaydi, lekin GROUP BY li aggregate o'sha row larni bittaga siqadi, window function esa har bir row uchun qiymat qaytaradi va hammasini saqlaydi.
S: ROW_NUMBER, RANK va DENSE_RANK?
Tenglikda: ROW_NUMBER har xil ketma-ket raqam beradi; RANK bir xil raqam berib, keyin o'tkazib yuboradi (1,1,3); DENSE_RANK bir xil raqam berib, bo'shliq qoldirmaydi (1,1,2).
S: Har bir guruhdan top 3 row ni qanday olasiz?
CTE ichida ROW_NUMBER() OVER (PARTITION BY group_col ORDER BY sort_col DESC), keyin tashqi query da WHERE rn <= 3.
S: Nega window function ni WHERE da filtrlab bo'lmaydi?
Chunki window function lar SELECT bilan (5-qadam), WHERE dan (2-qadam) keyin hisoblanadi. Qiymat hali mavjud emas. Query ni CTE yoki derived table ga o'rab, tashqarida filtrlang.
S: OVER() ichidagi ORDER BY nimani o'zgartiradi?
U partition ichidagi row larni tartiblaydi va aggregate lar uchun standart frame ni "partition boshidan joriy row gacha" ga o'zgartiradi — ya'ni SUM ni running total ga aylantiradi.
S: Oydan-oyga o'sishni qanday hisoblaysiz?
(n - LAG(n) OVER (ORDER BY month)) * 100.0 / LAG(n) OVER (ORDER BY month). Avval har bir oy row sifatida mavjudligiga ishonch hosil qiling, aks holda LAG noto'g'ri davrga qadam tashlaydi.
S: Frame da ROWS va RANGE?
ROWS jismoniy row larni sanaydi; RANGE bir xil ORDER BY qiymatiga ega row larni bitta birlik deb qaraydi. Ular faqat tartiblash qiymatlari takrorlanganda farq qiladi.
S: SUM(COUNT(*)) OVER () nima qilyapti?
Ichkaridagi COUNT(*) har bir guruh bo'yicha aggregate qiladi; window function esa o'sha guruh yig'indilarini barcha guruhlar bo'yicha qo'shadi — natijada har bir guruhning umumiy natijadagi ulushi bitta query da chiqadi.
Xulosa
- Window function bog'liq row lar ustida ularni siqmasdan hisoblaydi — tafsilot qoladi, xulosa column sifatida qo'shiladi.
OVER ()= barcha row lar ·OVER (PARTITION BY x)= har bir guruhda qaytadan ·OVER (ORDER BY x)= running / to'planuvchi.- Ranking:
ROW_NUMBER(doim unique),RANK(teng qiymatlar bir xil, keyin o'tkazib yuboriladi),DENSE_RANK(teng qiymatlar bir xil, bo'shliqsiz).ROW_NUMBERni aniq qilish uchun ajratuvchi qo'shing. - Guruh bo'yicha Top-N = CTE ichida
ROW_NUMBER() OVER (PARTITION BY ... ORDER BY ...), keyin filtr. Bu — klassik intervyu topshirig'i. - Window function ni
WHEREda filtrlab bo'lmaydi — uSELECTqadamida hisoblanadi. CTE ishlating. LAG/LEADqo'shni row larga qaraydi — avval to'liq sana qatorini yarating, aks holda davrlar arifmetikasi indamay noto'g'ri davrlarni solishtiradi.- Frame lar (
ROWS BETWEEN ...) window ni belgilaydi: running total, moving average, oldinga qarab yig'indi. NTILE(n)row larni segmentlarga bo'ladi (kvartil, RFM ball);PERCENT_RANK0–1 oralig'ida nisbiy o'rin beradi.- Window function lar
GROUP BYustida ishlashi mumkin —SUM(COUNT(*)) OVER ()har bir guruhning umumiy ulushini beradi.
Keyingi: 8-bob — string va date function lar hamda CASE WHEN, ya'ni query ichida qiymatlarni qayta shakllantirish va kategoriyalash vositalari.
Bu bobni bepul o'qidingiz.
Kitob o'rgatadi, lekin sizning kodingiz nega ishlamaganini ayta olmaydi. Kursda uy vazifangiz tekshiriladi.