Ko'pincha bizni qiymatning o'zi emas, balki biror narsa umuman bor yoki yo'qligi qiziqtiradi. Masalan: "kamida bitta buyurtma qilgan mijozlarni top", "hech qachon buyurtma bermaganlarni top". Bunday savollarda biz hisoblamoqchi emasmiz — biz faqat mavjudligini tekshirmoqchimiz.
Aynan shu uchun SQL da EXISTS operatori bor. EXISTS ichidagi quyi so'rov kamida bitta qator qaytarsa TRUE, hech qanday qator qaytarmasa FALSE bo'ladi.
Misollar uchun mijozlar va buyurtmalar jadvallaridan foydalanamiz.
mijozlar:
| id | ism | shahar | yosh |
|---|---|---|---|
| 1 | Ali | Toshkent | 25 |
| 2 | Vali | Samarqand | 30 |
| 3 | Soli | Toshkent | 22 |
| 4 | Guli | Buxoro | 35 |
| 5 | Dilnoza | Toshkent | 28 |
| 6 | Jasur | Samarqand | 40 |
buyurtmalar (mijoz_id → mijozlar.id):
| id | mijoz_id | mahsulot_id | soni | sana |
|---|---|---|---|---|
| 1 | 1 | 1 | 1 | 2024-01-15 |
| 2 | 1 | 4 | 3 | 2024-01-20 |
| 3 | 2 | 2 | 1 | 2024-02-05 |
| 4 | 3 | 6 | 10 | 2024-02-10 |
| 5 | 5 | 3 | 2 | 2024-03-01 |
| 6 | 1 | 5 | 5 | 2024-03-15 |
| 7 | 6 | 8 | 4 | 2024-03-20 |
E'tibor bering: buyurtmalar jadvalida mijoz_id qiymatlari faqat 1, 2, 3, 5, 6. Demak id = 4 bo'lgan Guli hech qachon buyurtma qilmagan.
EXISTS dan keyin qavs ( ) ichida bitta quyi so'rov yoziladi. SQL bu ichki so'rovni ishga tushiradi va shunchaki qaraydi:
EXISTS natijasi TRUE,EXISTS natijasi FALSE.Ichki so'rov nima qaytargani muhim emas — faqat qator bor yoki yo'qligi muhim. Shuning uchun odatda SELECT 1 yoziladi (1 raqami shartli, "biror narsa" degani):
SELECT ism
FROM mijozlar
WHERE EXISTS (SELECT 1 FROM buyurtmalar);Bu yerda ichki so'rov mijozga bog'lanmagan — buyurtmalar jadvalida qatorlar bo'lgani uchun u har doim TRUE. Natijada barcha mijozlar chiqib ketadi. Bu bizga kerakli javob emas: bizga har bir mijoz uchun aynan o'sha mijozning buyurtmasi bor-yo'qligini tekshirish kerak.
Sehr mana shu yerda boshlanadi. Tashqi so'rovdagi jadvalga taxallus (alias) beramiz — masalan mijozlar m — va ichki so'rov ichida shu m ga murojaat qilamiz:
SELECT ism
FROM mijozlar m
WHERE EXISTS (
SELECT 1
FROM buyurtmalar b
WHERE b.mijoz_id = m.id
);Ichki so'rov endi tashqi so'rovning joriy qatoriga bog'langan: b.mijoz_id = m.id. Bunday quyi so'rov bog'liq quyi so'rov (correlated subquery) deb ataladi — chunki u tashqi so'rovsiz o'zicha ishlay olmaydi, undagi m.id ga "bog'liq".
SQL har bir mijoz uchun ichki so'rovni qaytadan ishga tushiradi:
m.id = 1): buyurtmalar da mijoz_id = 1 bo'lgan qatorlar bormi? — Ha (1, 2, 6). EXISTS → TRUE → Ali chiqadi.m.id = 4): buyurtmalar da mijoz_id = 4 bo'lgan qator bormi? — Yo'q. EXISTS → FALSE → Guli chiqmaydi.Shu tarzda barcha mijozlar tekshiriladi. Natijani alifbo tartibida ko'rsatish uchun ORDER BY ism qo'shamiz:
SELECT ism
FROM mijozlar m
WHERE EXISTS (SELECT 1 FROM buyurtmalar b WHERE b.mijoz_id = m.id)
ORDER BY ism;Natija:
Ali
Dilnoza
Jasur
Soli
ValiFaqat Guli ro'yxatdan tushib qoldi — chunki uning hech qanday buyurtmasi yo'q.
Muhim:
EXISTSichidagiSELECTda nima yozsangiz ham (SELECT 1,SELECT *,SELECT ism) — natija bir xil bo'ladi. ChunkiEXISTSustunlarning qiymatiga emas, faqat qator bormi-yo'qmi degan savolga qaraydi. Shu sababli odatda eng soddasi —SELECT 1— yoziladi.
Bog'liq quyi so'rovda ikkala jadvalga ham murojaat qilamiz, shuning uchun qaysi id qaysi jadvalga tegishli ekanini aniq ko'rsatishimiz kerak. Taxalluslar (m va b) aynan shu chalkashlikni yo'qotadi:
m.id — tashqi mijozlar jadvalining id ustuni,b.mijoz_id — ichki buyurtmalar jadvalining mijoz_id ustuni.Agar taxallus bermasak va shunchaki mijoz_id = id deb yozsak, SQL id qaysi jadvalga tegishli ekanini aniq tushunmasligi mumkin. Shuning uchun bog'liq quyi so'rovlarda taxallus berish — yaxshi odat.
Eslatma:
EXISTSning teskarisiNOT EXISTS. Masalan,WHERE NOT EXISTS (...)bilan hech qachon buyurtma qilmagan mijozlarni (ya'ni Guli ni) topish mumkin. Bu bilan keyingi mavzularda yaqindan tanishasiz.
Pastdagi kod oynasida mijozlar va buyurtmalar jadvallari allaqachon yaratilgan va to'ldirilgan. Sizning vazifangiz — kamida bitta buyurtma qilgan mijozlarning ismini alifbo tartibida chiqarish. Buning uchun EXISTS va bog'liq quyi so'rovdan (b.mijoz_id = m.id) foydalaning.