Subquery va CTE
2-bobda query table qaytaradi degan fikr aytilgan edi. Bu bob shundan foyda oladi: agar query table qaytarsa, uni table kutilayotgan har qanday joyda ishlatish mumkin — WHERE ichida, FROM ichida, hatto SELECT ichida ham. Subquery shunchaki shu.
Shu yerda chalkash query lar o'qishli bo'lib qoladi ham, chunki CTE besh qavat qavs o'rniga har bir qadamga nom berish imkonini beradi.
Subquery nima — uchta o'rin
Subquery (ichki query) — boshqa ifoda ichida, doim qavs ichida yozilgan SELECT. Uni qayerga qo'yishingiz qanday shakl qaytarishi kerakligini belgilaydi.
| O'rni | Nima qaytarishi kerak | Nomi | Odatdagi ishlatilishi |
|---|---|---|---|
SELECT ichida |
Aynan bitta row, bitta column | Scalar subquery | Har bir row ni umumiy natija bilan solishtirish |
WHERE da = bilan |
Aynan bitta row, bitta column | Scalar subquery | "maksimum", "o'rtacha" |
WHERE da IN/EXISTS |
Bitta column, ko'p row | Row subquery | A'zolikni tekshirish |
FROM ichida |
To'liq table | Derived table | Ikki marta aggregate; alias bo'yicha filtrlash |
Scalar subquery
Bitta qiymat qaytaradigan subquery ni qiymat ishlatish mumkin bo'lgan har qanday joyda ishlatsa bo'ladi.
SELECT title, price, (SELECT ROUND(AVG(price)) FROM courses) AS avg_price, price - (SELECT AVG(price) FROM courses) AS diff_from_avg FROM courses ORDER BY price DESC;
| title | price | avg_price | diff_from_avg |
|---|---|---|---|
| Deep Learning | 1 550 000 | 1 183 333 | 366 666.667 |
| Project Management | 1 500 000 | 1 183 333 | 316 666.667 |
| Financial Analysis | 1 500 000 | 1 183 333 | 316 666.667 |
| Machine Learning | 1 450 000 | 1 183 333 | 266 666.667 |
| Probability | 1 250 000 | 1 183 333 | 66 666.667 |
| Python Basics | 1 200 000 | 1 183 333 | 16 666.667 |
| Statistics 101 | 1 200 000 | 1 183 333 | 16 666.667 |
| Linear Algebra | 1 200 000 | 1 183 333 | 16 666.667 |
| Web Development | 1 150 000 | 1 183 333 | -33 333.333 |
| Java Basics | 1 150 000 | 1 183 333 | -33 333.333 |
| Excel for Business | 1 100 000 | 1 183 333 | -83 333.333 |
| Graphic Design | 950 000 | 1 183 333 | -233 333.333 |
| Data Visualization | 900 000 | 1 183 333 | -283 333.333 |
| UX Design | 850 000 | 1 183 333 | -333 333.333 |
| SQL for Analytics | 800 000 | 1 183 333 | -383 333.333 |
15 qator
1 ms
WHERE da u "o'rtachaga / maksimumga nisbatan" savoliga javob beradi:
SELECT title, price FROM courses WHERE price > (SELECT AVG(price) FROM courses); -- Machine Learning, Deep Learning SELECT enrollment_id, grade FROM enrollments WHERE grade = (SELECT MAX(grade) FROM enrollments); -- 13-enrollment, baho 100
1-natija
| title | price |
|---|---|
| Python Basics | 1 200 000 |
| Statistics 101 | 1 200 000 |
| Machine Learning | 1 450 000 |
| Project Management | 1 500 000 |
| Linear Algebra | 1 200 000 |
| Deep Learning | 1 550 000 |
| Financial Analysis | 1 500 000 |
| Probability | 1 250 000 |
8 qator
2-natija
| enrollment_id | grade |
|---|---|
| 135 | 100 |
| 322 | 100 |
| 500 | 100 |
| 699 | 100 |
| 814 | 100 |
| 1 096 | 100 |
| 1 202 | 100 |
| 1 832 | 100 |
| 1 862 | 100 |
| 2 126 | 100 |
| 2 128 | 100 |
| 2 161 | 100 |
| 2 377 | 100 |
| 2 424 | 100 |
14 qator
1 ms
:::gotcha ⚠️ Bittadan ko'p row = runtime xato
WHERE price = (SELECT price FROM courses) subquery bittadan ko'p row qaytargan zahoti xato beradi. Ko'p qiymat bo'lishi mumkin bo'lsa, = o'rniga IN ishlating. Agar subquery hech qanday row qaytarmasa, u NULL bo'ladi — solishtirish UNKNOWN ga aylanadi va tashqi query indamay hech narsa qaytarmaydi.
:::
Derived table (FROM dagi subquery)
FROM dagi subquery o'sha query uchun vaqtinchalik table bo'ladi. Unga alias berish shart. Bu — aggregate ustidan aggregate qilish usuli, buni bitta GROUP BY uddalay olmaydi.
-- "O'rtacha hisobda bitta course da nechta enrollment bor?" SELECT ROUND(AVG(cnt), 2) AS avg_enrollments_per_course FROM ( SELECT course_id, COUNT(*) AS cnt FROM enrollments GROUP BY course_id ) AS per_course; -- 4.0 (sanoqlar 5, 5, 3, 3, 4)
| avg_enrollments_per_course |
|---|
| 178.57 |
1 qator
1 ms
Ichki query 20 ta enrollment ni 5 ta row ga siqadi; tashqi query esa o'sha 5 ta sonning o'rtachasini oladi. Ikki daraja aggregation, ikkita query.
U 2-bobdagi alias bo'yicha filtrlab bo'lmaslik muammosini ham hal qiladi:
-- WHERE alias ni ko'rmaydi — lekin derived table ning column ini ko'radi SELECT * FROM ( SELECT title, ROUND(price * 1.0 / credits) AS per_credit FROM courses ) AS t WHERE per_credit > 400000 ORDER BY per_credit DESC; -- Deep Learning 600000, SQL for Analytics 500000, -- Machine Learning 500000, Data Visualization 466667
| title | per_credit |
|---|---|
| Excel for Business | 550 000 |
| Project Management | 500 000 |
| Financial Analysis | 500 000 |
3 qator
0 ms
Correlated subquery lar Oddiy subquery bir marta ishlaydi. Correlated subquery esa tashqi query ning column iga murojaat qiladi, shuning uchun u nazariy jihatdan har bir tashqi row uchun qaytadan ishlaydi.
SELECT s.first_name, (SELECT COUNT(*) FROM enrollments e WHERE e.student_id = s.student_id) AS courses, (SELECT ROUND(AVG(grade),1) FROM enrollments e WHERE e.student_id = s.student_id) AS avg_grade FROM students s ORDER BY courses DESC, s.first_name;
| first_name | courses | avg_grade |
|---|---|---|
| Zulfiya | 19 | 71.1 |
| Shohrux | 17 | 74 |
| Gulnora | 16 | 71.7 |
| Sardor | 16 | 71.2 |
| Aziz | 15 | 76.5 |
| Gulnora | 15 | 77.5 |
| Nilufar | 15 | 73.4 |
| Otabek | 15 | 71.7 |
| Shahnoza | 15 | 70.7 |
| Shohrux | 15 | 73.2 |
| Akmal | 14 | 70.6 |
| Aziza | 14 | 75.5 |
| Dilnoza | 14 | 72.8 |
| Kamola | 14 | 73.4 |
| Kamola | 14 | 77.8 |
… 300 qatordan birinchi 15 tasi
300 qator
35 ms
Nazariy jihatdan ichki query har bir tashqi row uchun bir marta ishlaydi: bu yerda 10 student × 2 subquery = 20 marta, million row li table da esa 1 000 000 marta. Zamonaviy optimizer lar oddiy holatlarni ko'pincha join ga aylantiradi, lekin bunga tayanmang. GROUP BY li LEFT JOIN xuddi shu ishni bir o'tishda qiladi va yaxshi masshtablanadi:
sql run
SELECT s.first_name, COUNT(e.enrollment_id) AS courses,
ROUND(AVG(e.grade),1) AS avg_grade
FROM students s LEFT JOIN enrollments e ON s.student_id = e.student_id
GROUP BY s.student_id, s.first_name;
Kichik data da tushunarlilik uchun correlated subquery, katta data da join ishlating.
EXISTS va NOT EXISTS
EXISTS subquery ni oladi va u kamida bitta row hosil qilsa TRUE qaytaradi. Row larning ichida nima borligi uni qiziqtirmaydi — shuning uchun hamma uning ichiga SELECT 1 yozadi.
-- Kamida bitta active enrollment i bor student lar SELECT s.first_name FROM students s WHERE EXISTS ( SELECT 1 FROM enrollments e WHERE e.student_id = s.student_id AND e.status = 'active' ); -- Aziza, Dilnoza, Malika, Zarina, Ulugbek -- Hech qachon yiqilmagan student lar SELECT s.first_name FROM students s WHERE NOT EXISTS ( SELECT 1 FROM enrollments e WHERE e.student_id = s.student_id AND e.status = 'failed' ); -- Jasur va Sevara dan boshqa hamma
1-natija
| first_name |
|---|
| Shahnoza |
| Doston |
| Zulfiya |
| Kamola |
| Gulnora |
| Madina |
| Sardor |
| Jasur |
| Rustam |
| Madina |
| Shahnoza |
| Aziza |
| Aziza |
| Rustam |
| Dilnoza |
… 238 qatordan birinchi 15 tasi
238 qator
2-natija
| first_name |
|---|
| Shahnoza |
| Doston |
| Gulnora |
| Bekzod |
| Doston |
| Madina |
| Sardor |
| Dilnoza |
| Jasur |
| Rustam |
| Bekzod |
| Otabek |
| Madina |
| Shahnoza |
| Rustam |
… 160 qatordan birinchi 15 tasi
160 qator
22 ms
IN``EXISTS
Nimani solishtiradiQiymatni qiymatlar ro'yxati bilanRow mavjudmi yo'qmi
Erta to'xtaydimiYo'q — butun ro'yxatni quradiHa — birinchi mos kelganda to'xtaydi
Inkor qilinganda NULL ga xavfsizmiYo'q — NOT IN buziladiHa
Nimaga yaxshiQisqa literal ro'yxatlarKatta table lardagi correlated tekshiruvlar
:::tip 💡 Standart tanlov — NOT EXISTS
"Bog'liq row i yo'q" degani uchun NOT EXISTS NULL lardan qat'i nazar to'g'ri ishlaydi, ingliz jumlasidek o'qiladi va boshqa variantlardan kam bo'lmagan tezlikda ishlaydi. 3-bob NOT IN qanday buzilishini aynan ko'rsatgan edi.
:::
CTE — WITH clause
CTE (Common Table Expression) — ichkariga ko'mib emas, asosiy query dan oldin nom berib yoziladigan derived table. Natija bir xil, o'qishlilik esa ancha yaxshi.
WITH student_stats AS ( SELECT student_id, COUNT(*) AS courses, AVG(grade) AS avg_grade FROM enrollments WHERE grade IS NOT NULL GROUP BY student_id ) SELECT s.first_name, st.courses, ROUND(st.avg_grade, 1) AS avg_grade FROM student_stats st JOIN students s ON s.student_id = st.student_id WHERE st.avg_grade > (SELECT AVG(grade) FROM enrollments) ORDER BY st.avg_grade DESC;
| first_name | courses | avg_grade |
|---|---|---|
| Otabek | 3 | 87.3 |
| Shahnoza | 3 | 86.3 |
| Akmal | 2 | 84 |
| Zulfiya | 2 | 84 |
| Bekzod | 8 | 82.8 |
| Aziz | 2 | 82.5 |
| Shahnoza | 4 | 82.3 |
| Doston | 5 | 82.2 |
| Rustam | 4 | 81.8 |
| Gulnora | 9 | 81.6 |
| Ulug'bek | 6 | 81 |
| Nilufar | 3 | 81 |
| Aziz | 6 | 80.8 |
| Malika | 4 | 80.8 |
| Bekzod | 6 | 80.3 |
… 147 qatordan birinchi 15 tasi
147 qator
1 ms
- Nomlangan qadamlar.
WITH monthly_sales AS (...)o'zini o'zi hujjatlaydi; 3-darajadagi qavs esa yo'q. - Qayta ishlatiladi. CTE ga bitta query ichida bir necha marta murojaat qilish mumkin; derived table ni esa takrorlash kerak.
- Debug qilish oson. Talabalar qolgan qismini yozishdan oldin faqat CTE tanasini ishga tushirib tekshirishi mumkin.
- Rekursiya uchun majburiy. Recursive query yozishning boshqa yo'li yo'q.
Bir nechta CTE ni zanjirlash
Bir nechta CTE ni vergul bilan ajrating. Har biri o'zidan oldin e'lon qilinganlarga murojaat qila oladi, shuning uchun murakkab hisobot o'qishli pipeline ga aylanadi.
WITH graded AS ( -- 1-qadam: faqat haqiqatan bahosi bor enrollment lar SELECT * FROM enrollments WHERE grade IS NOT NULL ), course_avg AS ( -- 2-qadam: har bir course bo'yicha o'rtacha SELECT course_id, COUNT(*) AS n, AVG(grade) AS avg_grade FROM graded GROUP BY course_id ), overall AS ( -- 3-qadam: butun maktab uchun bitta son SELECT AVG(grade) AS school_avg FROM graded ) SELECT c.title, ca.n AS graded, ROUND(ca.avg_grade, 1) AS course_avg, ROUND((SELECT school_avg FROM overall), 1) AS school_avg, CASE WHEN ca.avg_grade > (SELECT school_avg FROM overall) THEN 'yuqori' ELSE 'past' END AS vs_school FROM course_avg ca JOIN courses c ON c.course_id = ca.course_id ORDER BY ca.avg_grade DESC;
| title | graded | course_avg | school_avg | vs_school |
|---|---|---|---|---|
| Excel for Business | 122 | 79.9 | 73 | yuqori |
| Python Basics | 132 | 79.2 | 73 | yuqori |
| UX Design | 118 | 76.1 | 73 | yuqori |
| Web Development | 118 | 75.2 | 73 | yuqori |
| Project Management | 131 | 75.1 | 73 | yuqori |
| Financial Analysis | 135 | 74.7 | 73 | yuqori |
| SQL for Analytics | 146 | 74.3 | 73 | yuqori |
| Data Visualization | 119 | 74.2 | 73 | yuqori |
| Java Basics | 127 | 73.9 | 73 | yuqori |
| Graphic Design | 147 | 73.5 | 73 | yuqori |
| Machine Learning | 125 | 69.4 | 73 | past |
| Linear Algebra | 140 | 68.3 | 73 | past |
| Probability | 138 | 65.6 | 73 | past |
| Statistics 101 | 128 | 63.6 | 73 | past |
14 qator
1 ms
Recursive CTE
Recursive CTE o'ziga o'zi murojaat qiladi. Uning UNION ALL bilan birlashtirilgan ikkita qismi bor: anchor (boshlang'ich row lar) va rekursiv qadam (bir row dan keyingisiga qanday o'tish). Rekursiv qadam hech narsa qaytarmagan paytda u to'xtaydi.
WITH RECURSIVE numbers(n) AS ( SELECT 1 -- anchor: qayerdan boshlaymiz UNION ALL SELECT n + 1 FROM numbers -- rekursiv qadam WHERE n < 10 -- TO'XTASH sharti — buni hech qachon tashlab ketmang ) SELECT n FROM numbers; -- 1 2 3 4 5 6 7 8 9 10
| n |
|---|
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
| 10 |
10 qator
0 ms
Analytics uchun haqiqatan foydali variant — to'liq sana qatorini yaratish, shunda data si yo'q oylar ham hisobotda nol bo'lib chiqadi:
WITH RECURSIVE months(m) AS ( SELECT '2025-09' UNION ALL SELECT strftime('%Y-%m', DATE(m || '-01', '+1 month')) FROM months WHERE m < '2026-09' ) SELECT months.m AS month, COUNT(e.enrollment_id) AS enrollments FROM months LEFT JOIN enrollments e ON strftime('%Y-%m', e.enrolled_at) = months.m GROUP BY months.m ORDER BY months.m;
| month | enrollments |
|---|---|
| 2025-09 | 1 188 |
| 2025-10 | 104 |
| 2025-11 | 0 |
| 2025-12 | 0 |
| 2026-01 | 0 |
| 2026-02 | 0 |
| 2026-03 | 0 |
| 2026-04 | 0 |
| 2026-05 | 0 |
| 2026-06 | 0 |
| 2026-07 | 0 |
| 2026-08 | 0 |
| 2026-09 | 0 |
13 qator
7 ms
Endi 13 ta oyning hammasi chiqadi — 2025-yil sentyabri 6 bilan, 2026-yil fevrali 12 bilan, 2026-yil sentyabri 2 bilan, va o'nta bo'sh oy 0 bilan. Yaratilgan qatorsiz o'sha oylar ko'rinmas edi, natijaning chiziqli grafigi esa juda chalg'ituvchi bo'lardi.
Yana bir klassik ishlatilishi — iyerarxiya bo'ylab yurish: xodimning butun rahbariyat zanjiri yoki chuqurligi noma'lum kategoriya daraxti.
Tugatuvchi WHERE siz recursive CTE database uni to'xtatgunicha yoki disk to'lguncha aylanaveradi. Rekursiv SELECT ni yozishdan oldin WHERE ni yozing. PostgreSQL va SQLite RECURSIVE keyword ini talab qiladi; SQL Server esa uni ishlatmaydi.
Subquery, JOIN va CTE — qaysi birini tanlash
| Vaziyat | Eng mos vosita | Nega |
|---|---|---|
| Boshqa table dan column lar kerak | JOIN | Join aynan shu uchun mavjud |
| Faqat bor/yo'q tekshiruvi kerak | EXISTS | Birinchi mos kelganda to'xtaydi; fan-out yo'q |
| Har bir row ga bitta umumiy son kerak | Scalar subquery yoki window function | Arzon va tabiiy o'qiladi |
| Aggregate ustidan aggregate kerak | Derived table / CTE | Ikki daraja GROUP BY ikkita query talab qiladi |
| Query ~15 qatordan uzun | CTE | Nomlangan qadamlar ichma-ich qavslardan yaxshi |
| Bir xil oraliq natija ikki marta kerak | CTE | Bir marta e'lon qiling, ko'p marta ishlating |
| Iyerarxiya yoki qator yaratish | Recursive CTE | Buni boshqa hech narsa qila olmaydi |
Ular doim ham bir-birining o'rnini bosmaydi. Ko'p tomonga join row larni takrorlaydi (fan-out, 5-bob); EXISTS va IN esa hech qachon takrorlamaydi. Shuning uchun:
```sql run -- 8 ta row — student har bir mos enrollment uchun bir marta chiqadi SELECT s.first_name FROM students s JOIN enrollments e ON s.student_id = e.student_id WHERE e.status = 'completed';
-- 8 ta har xil student — har biri aynan bir marta SELECT s.first_name FROM students s WHERE EXISTS (SELECT 1 FROM enrollments e WHERE e.student_id = s.student_id AND e.status = 'completed'); ```
Faqat mos keluvchi bor-yo'qligini bilish kerak bo'lsa, EXISTS ishlating. Join ni tozalash uchun SELECT DISTINCT ga qo'l cho'zish — aslida boshidan EXISTS kerak bo'lganining belgisi.
Mashqlar to'plami
-- 1. O'rtachadan qimmat course lar SELECT title, price FROM courses WHERE price > (SELECT AVG(price) FROM courses); -- 2. Eng yuqori o'rtacha bahoga ega student(lar) 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 FROM avg_per_student a JOIN students s USING (student_id) WHERE a.avg_grade = (SELECT MAX(avg_grade) FROM avg_per_student); -- 3. Machine Learning ni oladigan, lekin Python Basics ni olmaydigan student lar SELECT s.first_name FROM students s WHERE EXISTS (SELECT 1 FROM enrollments e WHERE e.student_id = s.student_id AND e.course_id = 5) AND NOT EXISTS (SELECT 1 FROM enrollments e WHERE e.student_id = s.student_id AND e.course_id = 1); -- 4. Bitta course ga to'g'ri keladigan o'rtacha enrollment soni SELECT ROUND(AVG(cnt),2) FROM ( SELECT course_id, COUNT(*) AS cnt FROM enrollments GROUP BY course_id ) t; -- 5. Har bir course ning barcha enrollment lardagi ulushi WITH per_course AS ( SELECT course_id, COUNT(*) AS n FROM enrollments GROUP BY course_id ) SELECT c.title, p.n, ROUND(100.0 * p.n / (SELECT SUM(n) FROM per_course), 1) AS pct_of_all FROM per_course p JOIN courses c USING (course_id) ORDER BY pct_of_all DESC; -- 6. Hech qachon yiqilmagan student lar SELECT first_name FROM students s WHERE NOT EXISTS (SELECT 1 FROM enrollments e WHERE e.student_id = s.student_id AND e.status = 'failed'); -- 7. 1 dan 12 gacha sonlar (rekursiv) WITH RECURSIVE n(x) AS (SELECT 1 UNION ALL SELECT x+1 FROM n WHERE x < 12) SELECT x FROM n; -- 8. Qayta yozish mashqi: #1 ni subquery emas, CTE ko'rinishida ifodalang WITH stats AS (SELECT AVG(price) AS avg_price FROM courses) SELECT c.title, c.price FROM courses c, stats WHERE c.price > stats.avg_price;
1-natija
| title | price |
|---|---|
| Python Basics | 1 200 000 |
| Statistics 101 | 1 200 000 |
| Machine Learning | 1 450 000 |
| Project Management | 1 500 000 |
| Linear Algebra | 1 200 000 |
| Deep Learning | 1 550 000 |
| Financial Analysis | 1 500 000 |
| Probability | 1 250 000 |
8 qator
2-natija
| first_name | avg_grade |
|---|---|
| Otabek | 87.3 |
1 qator
3-natija
| first_name |
|---|
| Gulnora |
| Doston |
| Sardor |
| Madina |
| Rustam |
| Shahnoza |
| Shahnoza |
| Dilnoza |
| Aziz |
| Ulug'bek |
| Akmal |
| Aziz |
| Kamola |
| Aziz |
| Shohrux |
… 74 qatordan birinchi 15 tasi
74 qator
4-natija
| ROUND(AVG(cnt),2) |
|---|
| 178.57 |
1 qator
5-natija
| title | n | pct_of_all |
|---|---|---|
| Linear Algebra | 200 | 8 |
| Python Basics | 193 | 7.7 |
| Financial Analysis | 189 | 7.6 |
| Java Basics | 187 | 7.5 |
| Probability | 188 | 7.5 |
| SQL for Analytics | 186 | 7.4 |
| Graphic Design | 179 | 7.2 |
| Statistics 101 | 174 | 7 |
| Web Development | 174 | 7 |
| Project Management | 170 | 6.8 |
| Data Visualization | 167 | 6.7 |
| Machine Learning | 167 | 6.7 |
| Excel for Business | 165 | 6.6 |
| UX Design | 161 | 6.4 |
14 qator
6-natija
| first_name |
|---|
| Shahnoza |
| Doston |
| Gulnora |
| Bekzod |
| Doston |
| Madina |
| Sardor |
| Dilnoza |
| Jasur |
| Rustam |
| Bekzod |
| Otabek |
| Madina |
| Shahnoza |
| Rustam |
… 160 qatordan birinchi 15 tasi
160 qator
7-natija
| x |
|---|
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
| 10 |
| 11 |
| 12 |
12 qator
8-natija
| title | price |
|---|---|
| Python Basics | 1 200 000 |
| Statistics 101 | 1 200 000 |
| Machine Learning | 1 450 000 |
| Project Management | 1 500 000 |
| Linear Algebra | 1 200 000 |
| Deep Learning | 1 550 000 |
| Financial Analysis | 1 500 000 |
| Probability | 1 250 000 |
8 qator
37 ms
Intervyu savollari
S: Correlated subquery nima?
Tashqi query ning column iga murojaat qiladigan subquery; shuning uchun u har bir tashqi row uchun hisoblanadi va alohida ishlay olmaydi. U ifodali, lekin O(n) marta bajarilishi mumkin; JOIN + GROUP BY odatda yaxshiroq masshtablanadi.
S: CTE va subquery — unumdorlikda farq bormi?
Odatda yo'q: ko'p engine lar CTE ni derived table kabi inline qiladi. Farq — o'qishlilik va qayta ishlatish. Ikkita istisno: PostgreSQL 12 dan oldin CTE larni doim materializatsiya qilardi (optimizatsiya to'sig'i), va bir necha marta murojaat qilingan CTE engine materializatsiya qilmasa bir necha marta hisoblanishi mumkin.
S: Qachon subquery emas, aynan CTE ishlatish shart?
Rekursiya uchun, va bir xil oraliq natija bitta query ichida bir martadan ko'p kerak bo'lganda.
S: Recursive CTE ning ikkita qismi qaysilar?
Anchor member (boshlang'ich row lar) va CTE ga murojaat qiladigan rekursiv member, ular UNION ALL bilan birlashtiriladi, ustiga rekursiv member ni oxir-oqibat bo'sh qiladigan shart qo'shiladi.
S: "Kamida bitta tugatilgan course i bor student lar" uchun IN, EXISTS yoki JOIN?
EXISTS eng mos: u birinchi mos kelganda to'xtaydi va har bir student ni bir marta qaytaradi. JOIN student ni har bir tugatilgan course uchun bir marta qaytaradi (fan-out) va DISTINCT talab qiladi. IN bu yerda yaxshi, lekin inkor qilingan zahoti xavfli bo'lib qoladi.
S: SELECT ichidagi subquery bir nechta row qaytara oladimi?
Yo'q — u scalar (bitta row, bitta column) bo'lishi kerak, aks holda query bajarilish paytida xato beradi. Nol row qaytarish mumkin, u NULL beradi.
S: Oylik hisobotda data si yo'q oylarni qanday ko'rsatasiz?
To'liq oy qatorini yarating (recursive CTE yoki calendar table), keyin data ni unga LEFT JOIN qiling va data tomonidagi column ni COUNT qiling.
Xulosa
- Subquery — boshqa ifoda ichidagi
SELECT. Uning o'rni kerakli shaklini belgilaydi:SELECT/=da scalar,INuchun qiymatlar column i,FROMda butun table. - Scalar subquery har bir row yoniga umumiy xulosani qo'yadi. Derived table aggregate ustidan aggregate qilish va alias bo'yicha filtrlash imkonini beradi.
- Correlated subquery lar tashqi query ga murojaat qiladi va har bir row uchun ishlaydi — kichik data da tushunarli, kattasida sekin; masshtabda JOIN + GROUP BY ni afzal ko'ring.
EXISTS/NOT EXISTS"kamida bittasi bormi?" ga javob beradi, erta to'xtaydi, fan-out qilmaydi va NULL ga xavfsiz.- CTE (
WITH) har bir qadamga nom beradi. Ularni vergul bilan zanjirlab, ulkan query ni o'qishli pipeline ga aylantiring. - Recursive CTE (anchor + rekursiv qadam + to'xtash sharti) qator yaratadi va iyerarxiya bo'ylab yuradi — hisobotlarda bo'sh davrlarni 0 qilib ko'rsatish uchun ishlatiladi.
- JOIN ko'p tomonda row larni takrorlaydi,
EXISTSesa yo'q. Join dan keyinDISTINCTga qo'l cho'zish odatdaEXISTSkerak bo'lganini bildiradi.
Keyingi: 7-bob — window function lar, ular row laringizni yo'qotmasdan aggregate qiymat beradi. Bu — analytics intervyusidagi eng qimmatli SQL ko'nikmasi.
Bu bobni bepul o'qidingiz.
Kitob o'rgatadi, lekin sizning kodingiz nega ishlamaganini ayta olmaydi. Kursda uy vazifangiz tekshiriladi.