SQL so'rovi qaysi tartibda bajariladi
SQL so'rovi SELECT dan emas, FROM dan boshlab bajariladi. Shu tartib nega WHERE da alias ishlamasligi, ORDER BY da esa ishlashini tushuntiradi.
So'rovni SELECT dan boshlab yozamiz, lekin ma'lumotlar bazasi uni boshqa tartibda bajaradi. Shu bitta faktni bilsangiz, "nega alias topilmayapti?", "nega bu yerda SUM yozib bo'lmaydi?" kabi xatolarning ko'pchiligi o'z-o'zidan tushunarli bo'lib qoladi.
Yozish tartibi va bajarilish tartibi
Yozamiz:
SELECT ... FROM ... WHERE ... GROUP BY ... HAVING ... ORDER BY ... LIMIT ...Baza esa mantiqan shu tartibda ishlaydi:
FROMvaJOIN— jadvallar olinadi va birlashtiriladiWHERE— alohida qatorlar filtrlanadiGROUP BY— qolgan qatorlar guruhlarga bo'linadiHAVING— guruhlar filtrlanadiSELECT— ustunlar va ifodalar hisoblanadi, alias shu yerda paydo bo'ladi; window funksiyalar ham shu bosqichdaDISTINCT— takroriy qatorlar olib tashlanadiORDER BY— saralanadiLIMIT/OFFSET— natija kesiladi
Asosiy qoida: har bir bosqich faqat o'zidan oldingi bosqichlarda paydo bo'lgan narsani ko'radi.
Jadval: orders
| id | city | status | amount |
|---|---|---|---|
| 1 | Toshkent | paid | 120000 |
| 2 | Toshkent | paid | 300000 |
| 3 | Toshkent | cancelled | 500000 |
| 4 | Samarqand | paid | 80000 |
| 5 | Samarqand | paid | 90000 |
| 6 | Buxoro | paid | 40000 |
| 7 | Buxoro | cancelled | 70000 |
| 8 | Andijon | paid | 250000 |
Bitta so'rovni bosqichma-bosqich kuzatamiz
Vazifa: to'langan buyurtmalar bo'yicha har bir shaharning jami savdosi. Faqat jami 150 000 dan oshgan shaharlar, kattasidan boshlab, birinchi ikkitasi.
SELECT city, SUM(amount) AS jami
FROM orders
WHERE status = 'paid'
GROUP BY city
HAVING SUM(amount) > 150000
ORDER BY jami DESC
LIMIT 2;FROM orders— 8 ta qator.WHERE status = 'paid'— bekor qilingan 3 va 7-buyurtmalar tashlanadi, 6 ta qator qoladi.GROUP BY city— 4 ta guruh: Toshkent (120 000 + 300 000), Samarqand (80 000 + 90 000), Buxoro (40 000), Andijon (250 000).HAVING SUM(amount) > 150000— Buxoro (40 000) tushib qoladi.SELECT— har guruh uchuncityvajamihisoblanadi.ORDER BY jami DESC— Toshkent 420 000, Andijon 250 000, Samarqand 170 000.LIMIT 2— birinchi ikkitasi qoladi.
Natija:
| city | jami |
|---|---|
| Toshkent | 420000 |
| Andijon | 250000 |
E'tibor bering: Toshkentdagi 500 000 lik bekor qilingan buyurtma jamiga qo'shilmadi, chunki WHERE uni guruhlashdan oldin olib tashladi.
1-xulosa: WHERE da alias ishlamaydi
Narxga 12% QQS qo'shib, 300 000 dan oshganlarini chiqarmoqchimiz:
SELECT id, amount * 1.12 AS qqs_bilan
FROM orders
WHERE qqs_bilan > 300000;PostgreSQL xato beradi: column "qqs_bilan" does not exist. Sababi tartibda: WHERE 2-bosqichda ishlaydi, qqs_bilan esa faqat 5-bosqichda — SELECT da paydo bo'ladi.
To'g'ri yo'l — ifodani WHERE da qayta yozish:
SELECT id, amount * 1.12 AS qqs_bilan
FROM orders
WHERE amount * 1.12 > 300000;| id | qqs_bilan |
|---|---|
| 2 | 336000.00 |
| 3 | 560000.00 |
Ifoda uzun bo'lsa va uni ikki marta yozgingiz kelmasa, hisoblashni ichki so'rovga oling. Ichki so'rov tashqi so'rovning FROM bosqichida tayyor jadvalga aylanadi, shuning uchun alias tashqarida ko'rinadi:
SELECT id, qqs_bilan
FROM (
SELECT id, amount * 1.12 AS qqs_bilan
FROM orders
) t
WHERE qqs_bilan > 300000;WITH (CTE) bilan ham xuddi shunday ishlaydi.
2-xulosa: ORDER BY da alias ishlaydi
ORDER BY 7-bosqichda, SELECT dan keyin bajariladi — alias unga allaqachon ma'lum:
SELECT id, amount * 1.12 AS qqs_bilan
FROM orders
ORDER BY qqs_bilan DESC;Lekin PostgreSQL'da bitta nozik joy bor: alias ORDER BY da faqat yolg'iz turgan holda tanib olinadi. Uni ifoda ichida ishlatsangiz, yana column "qqs_bilan" does not exist chiqadi:
SELECT id, amount * 1.12 AS qqs_bilan
FROM orders
ORDER BY qqs_bilan / 1000;Bunday holda ham ifodani to'liq yozing yoki ichki so'rovdan foydalaning.
3-xulosa: agregat WHERE da emas, HAVING da
WHERE ishlayotganda guruhlar hali yo'q, shuning uchun unda SUM, COUNT, AVG ishlatib bo'lmaydi:
SELECT city, SUM(amount) AS jami
FROM orders
WHERE SUM(amount) > 150000
GROUP BY city;Xato: aggregate functions are not allowed in WHERE. Guruh bo'yicha shart HAVING ga yoziladi — yuqoridagi bosqichma-bosqich misoldagidek.
HAVING ham SELECT dan oldin ishlaydi, shuning uchun PostgreSQL'da HAVING jami > 150000 deb yozib bo'lmaydi — SUM(amount) ni qayta yozish kerak. MySQL bunga ruxsat beradi, lekin bu standart emas: so'rovni boshqa bazaga ko'chirsangiz, buziladi.
4-xulosa: window funksiyani WHERE da filtrlab bo'lmaydi
Har bir shahardagi eng katta to'langan buyurtma kerak. Birinchi urinish:
SELECT id, city, amount,
ROW_NUMBER() OVER (PARTITION BY city ORDER BY amount DESC) AS rn
FROM orders
WHERE status = 'paid' AND rn = 1;rn — alias, u WHERE ga ko'rinmaydi. ROW_NUMBER() ... ni to'g'ridan-to'g'ri WHERE ga yozsangiz ham bo'lmaydi: window functions are not allowed in WHERE. Window funksiyalar SELECT bosqichida, ya'ni WHERE, GROUP BY va HAVING dan keyin hisoblanadi.
Yechim — avval raqamlab olish, keyin tashqi so'rovda filtrlash:
WITH r AS (
SELECT id, city, amount,
ROW_NUMBER() OVER (PARTITION BY city ORDER BY amount DESC) AS rn
FROM orders
WHERE status = 'paid'
)
SELECT id, city, amount
FROM r
WHERE rn = 1
ORDER BY city;| id | city | amount |
|---|---|---|
| 8 | Andijon | 250000 |
| 6 | Buxoro | 40000 |
| 5 | Samarqand | 90000 |
| 2 | Toshkent | 300000 |
Bu tartibning yana bir oqibati: window funksiya faqat WHERE dan o'tgan qatorlarni ko'radi. Shu sababli Toshkent uchun 500 000 lik bekor qilingan buyurtma emas, 300 000 lik to'langani chiqdi.
5-xulosa: DISTINCT dan keyin faqat tanlangan ustunlar qoladi
Shaharlarni eng katta buyurtmasi bo'yicha saralamoqchimiz:
SELECT DISTINCT city
FROM orders
ORDER BY amount DESC;PostgreSQL: for SELECT DISTINCT, ORDER BY expressions must appear in select list. DISTINCT ishlab bo'lgach, har shahardan bitta qator qoladi — qaysi amount bo'yicha saralash kerakligi noma'lum. Nima bo'yicha saralashni aniq ayting:
SELECT city
FROM orders
GROUP BY city
ORDER BY MAX(amount) DESC;| city |
|---|
| Toshkent |
| Andijon |
| Samarqand |
| Buxoro |
6-xulosa: LIMIT eng oxirida ishlaydi
LIMIT natijani eng oxirida kesadi. Bundan ikkita amaliy xulosa chiqadi:
ORDER BYsizLIMIT 10— "qandaydir 10 ta qator". Baza ularni istalgan tartibda qaytarishi mumkin, bugun bir xil, ertaga boshqacha. Sahifalashda (LIMIT ... OFFSET ...) tartib doim aniq va takrorlanmas bo'lishi kerak, masalanORDER BY price DESC, id.GROUP BYli so'rovgaLIMIT 1qo'shish hisoblashni tezlashtirmaydi: guruhlarni tartiblash uchun avval hammasini hisoblash kerak.
Mantiqiy va jismoniy tartib
Yuqoridagi ro'yxat — mantiqiy tartib: u qaysi bosqichda nima ko'rinishini belgilaydi. Optimizator so'rovni jismonan boshqacha bajarishi mumkin — masalan, WHERE shartini JOIN dan oldin qo'llash yoki indeks bo'yicha darhol saralangan qatorlarni o'qish. Lekin natija doim mantiqiy tartib bo'yicha qanday bo'lsa, shunday chiqadi. Shuning uchun so'rov yozayotganda mantiqiy tartib bo'yicha fikrlang.
Xulosa
- Bajarilish tartibi:
FROM→WHERE→GROUP BY→HAVING→SELECT→DISTINCT→ORDER BY→LIMIT. SELECTdagi aliasWHEREvaHAVINGda ishlamaydi — ifodani qayta yozing yoki ichki so'rov ishlating.ORDER BYda ishlaydi (PostgreSQL'da faqat yolg'iz holda).- Agregat bo'yicha shart —
HAVINGda, qator bo'yicha shart —WHEREda. - Window funksiya natijasini filtrlash uchun CTE yoki ichki so'rov kerak.
LIMITdan oldin doim aniqORDER BYyozing.
Endi o'zingiz yechib ko'ring
O'rganganingizni mustahkamlang — so'rovingiz brauzerda darhol tekshiriladi.
