Saytdan foydalanishda muammoga duch kelsangiz, qo'llab-quvvatlash xizmatiga murojaat qiling: @fast_support_admin
SELECT asoslari7 daqiqa o'qish

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:

  1. FROM va JOIN — jadvallar olinadi va birlashtiriladi
  2. WHERE — alohida qatorlar filtrlanadi
  3. GROUP BY — qolgan qatorlar guruhlarga bo'linadi
  4. HAVING — guruhlar filtrlanadi
  5. SELECT — ustunlar va ifodalar hisoblanadi, alias shu yerda paydo bo'ladi; window funksiyalar ham shu bosqichda
  6. DISTINCT — takroriy qatorlar olib tashlanadi
  7. ORDER BY — saralanadi
  8. LIMIT / OFFSET — natija kesiladi

Asosiy qoida: har bir bosqich faqat o'zidan oldingi bosqichlarda paydo bo'lgan narsani ko'radi.

Jadval: orders

idcitystatusamount
1Toshkentpaid120000
2Toshkentpaid300000
3Toshkentcancelled500000
4Samarqandpaid80000
5Samarqandpaid90000
6Buxoropaid40000
7Buxorocancelled70000
8Andijonpaid250000

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.

To'g'ri yechim
SELECT city, SUM(amount) AS jami
FROM orders
WHERE status = 'paid'
GROUP BY city
HAVING SUM(amount) > 150000
ORDER BY jami DESC
LIMIT 2;
  1. FROM orders — 8 ta qator.
  2. WHERE status = 'paid' — bekor qilingan 3 va 7-buyurtmalar tashlanadi, 6 ta qator qoladi.
  3. GROUP BY city — 4 ta guruh: Toshkent (120 000 + 300 000), Samarqand (80 000 + 90 000), Buxoro (40 000), Andijon (250 000).
  4. HAVING SUM(amount) > 150000 — Buxoro (40 000) tushib qoladi.
  5. SELECT — har guruh uchun city va jami hisoblanadi.
  6. ORDER BY jami DESC — Toshkent 420 000, Andijon 250 000, Samarqand 170 000.
  7. LIMIT 2 — birinchi ikkitasi qoladi.

Natija:

cityjami
Toshkent420000
Andijon250000

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:

Noto'g'ri yondashuv
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:

To'g'ri yechim
SELECT id, amount * 1.12 AS qqs_bilan
FROM orders
WHERE amount * 1.12 > 300000;
idqqs_bilan
2336000.00
3560000.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:

To'g'ri yechim
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:

To'g'ri yechim
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:

Noto'g'ri yondashuv
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:

Noto'g'ri yondashuv
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:

Noto'g'ri yondashuv
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:

To'g'ri yechim
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;
idcityamount
8Andijon250000
6Buxoro40000
5Samarqand90000
2Toshkent300000

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:

Noto'g'ri yondashuv
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:

To'g'ri yechim
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 BY siz LIMIT 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, masalan ORDER BY price DESC, id.
  • GROUP BY li so'rovga LIMIT 1 qo'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.
  • SELECT dagi alias WHERE va HAVING da ishlamaydi — ifodani qayta yozing yoki ichki so'rov ishlating. ORDER BY da ishlaydi (PostgreSQL'da faqat yolg'iz holda).
  • Agregat bo'yicha shart — HAVING da, qator bo'yicha shart — WHERE da.
  • Window funksiya natijasini filtrlash uchun CTE yoki ichki so'rov kerak.
  • LIMIT dan oldin doim aniq ORDER BY yozing.

Endi o'zingiz yechib ko'ring

O'rganganingizni mustahkamlang — so'rovingiz brauzerda darhol tekshiriladi.

Telegram'da muhokama qilish