INNER, LEFT, RIGHT, FULL, CROSS, SELF JOIN
Muammodan boshlaylik
Sizda ikki jadval bor: foydalanuvchilar va buyurtmalar. Siz bitta so'rovda "kim qancha buyurtma bergan" degan savollarga javob olmoqchisiz. Lekin ma'lumotlar ikki alohida jadvalda. Ularni qanday birlashtirish kerak?
Yoki boshqa holat: buyurtma bergan foydalanuvchilar ro'yxatini chiqarmoqchisiz. Ba'zi foydalanuvchilar hali buyurtma bermaganmi — ularni ham ko'rsatish kerakmi? Ko'rsatmaslik kerakmi?
Ana shu savollarga javob — JOIN lar.
JOIN nima?
JOIN — ikki yoki undan ko'p jadvalning ma'lumotlarini birlashtirib, bitta natija to'plami hosil qilish. Ma'lumotlar orasidagi aloqa (odatda foreign key) orqali qaysi qatorlar mos kelishini aniqlaydi.
Hayotiy o'xshatma: ikkita ro'yxat — sinfdagi o'quvchilar va imtihon natijalari. Agar o'quvchi imtihon bergan bo'lsa — uning ismi va bahosi birgalikda chiqadi. Agar imtihon bermagan bo'lsa — natijalar ro'yxatida uning ismi yo'q. Endi savollar: faqat imtihon berganlarni ko'rish kerakmi? Yoki hamma o'quvchilar, imtihon bermaganlar ham? Ana shu farq — JOIN turlari.
Namuna jadvallar
Barcha misollar shu ikki jadval ustida:
CREATE TABLE foydalanuvchilar (
id SERIAL PRIMARY KEY,
ism TEXT NOT NULL
);
CREATE TABLE buyurtmalar (
id SERIAL PRIMARY KEY,
foydalanuvchi_id INT REFERENCES foydalanuvchilar(id),
mahsulot TEXT,
summa NUMERIC
);
INSERT INTO foydalanuvchilar VALUES (1, 'Ali'), (2, 'Vali'), (3, 'Soli');
INSERT INTO buyurtmalar VALUES
(1, 1, 'Noutbuk', 5000000),
(2, 1, 'Sichqon', 150000),
(3, 2, 'Klaviatura',350000);
-- Soli (id=3) buyurtma bermagan
INNER JOIN — faqat mos kelganlar
Ikkala jadvalda mos yozuv bor qatorlarni qaytaradi. Birida yo'q bo'lsa — natijaga tushmaydi.
SELECT f.ism, b.mahsulot, b.summa
FROM foydalanuvchilar f
INNER JOIN buyurtmalar b ON f.id = b.foydalanuvchi_id;
ism │ mahsulot │ summa
------+-------------+---------
Ali │ Noutbuk │ 5000000
Ali │ Sichqon │ 150000
Vali │ Klaviatura │ 350000
Soli buyurtma bermagan — u natijaga tushmadi.
INNER JOIN yoki shunchaki JOIN yozilsa — bir xil.
LEFT JOIN — chap jadval to'liq
Chap jadvaldagi (FROM dan keyingi) barcha qatorlar qaytariladi. O'ng jadvalda mos yozuv bo'lmasa — o'ng tomongi ustunlar NULL bo'ladi.
SELECT f.ism, b.mahsulot
FROM foydalanuvchilar f
LEFT JOIN buyurtmalar b ON f.id = b.foydalanuvchi_id;
ism │ mahsulot
------+------------
Ali │ Noutbuk
Ali │ Sichqon
Vali │ Klaviatura
Soli │ NULL ← buyurtma yo'q, lekin foydalanuvchi chiqdi
Amalda ko'p ishlatiladi: "barcha foydalanuvchilar, buyurtmasi bo'lmasa ham" holatlarida.
Hech qachon buyurtma bermagan foydalanuvchilarni topish:
SELECT f.ism
FROM foydalanuvchilar f
LEFT JOIN buyurtmalar b ON f.id = b.foydalanuvchi_id
WHERE b.id IS NULL; -- ← o'ng tarafda NULL = mos yozuv yo'q
ism
------
Soli
RIGHT JOIN — o'ng jadval to'liq
LEFT JOIN ning teskarisi. O'ng jadvaldagi barcha qatorlar qaytariladi, chap jadvalda mos yozuv yo'q bo'lsa — NULL.
SELECT f.ism, b.mahsulot
FROM foydalanuvchilar f
RIGHT JOIN buyurtmalar b ON f.id = b.foydalanuvchi_id;
Amalda kamdan-kam ishlatiladi — jadvallarni almashtirsa, LEFT JOIN bilan bir xil natija. Ko'pchilik dasturchilar faqat LEFT JOIN ishlatadi: tushunarli, izchil.
FULL JOIN — ikkalasi ham to'liq
Ikkala jadvalning barcha qatorlari qaytariladi. Biror tomonda mos yozuv yo'q bo'lsa — NULL.
SELECT f.ism, b.mahsulot
FROM foydalanuvchilar f
FULL JOIN buyurtmalar b ON f.id = b.foydalanuvchi_id;
ism │ mahsulot
------+------------
Ali │ Noutbuk
Ali │ Sichqon
Vali │ Klaviatura
Soli │ NULL
Amalda qo'llanishi: ikkala jadvalda ham "yetim" qatorlarni topish — masalan buyurtmasi yo'q foydalanuvchilar va foydalanuvchisi yo'q buyurtmalar.
CROSS JOIN — barcha kombinatsiyalar
Ikki jadvaldagi har bir qatorni boshqasining har bir qatori bilan birlashtiradi. 3 × 4 = 12 qator. ON sharti yo'q.
SELECT f.ism, b.mahsulot
FROM foydalanuvchilar f
CROSS JOIN buyurtmalar b;
ism │ mahsulot
------+------------
Ali │ Noutbuk
Ali │ Sichqon
Ali │ Klaviatura
Vali │ Noutbuk
Vali │ Sichqon
Vali │ Klaviatura
Soli │ Noutbuk
Soli │ Sichqon
Soli │ Klaviatura
Qachon kerak: kombinatsiyalar jadvalini yaratish — masalan barcha ranglar va o'lchamlar kombinatsiyasi. Katta jadvallarda ehtiyot bo'ling: 1000 × 1000 = 1,000,000 qator.
SELF JOIN — jadval o'zi bilan
Jadvalning o'zini o'zi bilan birlashtirish. Bir xil jadval ikki marta, har biriga boshqa alias beriladi.
Odatda qo'llanishi: ierarxik ma'lumotlar — xodim va uning rahbari bir xil xodimlar jadvalida.
CREATE TABLE xodimlar (
id INT PRIMARY KEY,
ism TEXT,
rahbar_id INT REFERENCES xodimlar(id) -- o'zi o'ziga reference
);
INSERT INTO xodimlar VALUES
(1, 'Kamol', NULL), -- rahbar yo'q (direktor)
(2, 'Jasur', 1), -- Kamolga bo'ysunadi
(3, 'Malika', 1), -- Kamolga bo'ysunadi
(4, 'Sherzod', 2); -- Jasurga bo'ysunadi
SELECT
x.ism AS xodim,
r.ism AS rahbar
FROM xodimlar x
LEFT JOIN xodimlar r ON x.rahbar_id = r.id; -- ← bir jadval, ikki alias
xodim │ rahbar
---------+--------
Kamol │ NULL
Jasur │ Kamol
Malika │ Kamol
Sherzod │ Jasur
Bir so'rovda bir nechta JOIN
JOIN lar zanjir bo'lib ketaveravaradi — har bir JOIN avvalgi natijaga yangi jadval birlashtiradi.
SELECT
f.ism,
b.mahsulot,
k.nomi AS kategoriya
FROM foydalanuvchilar f
JOIN buyurtmalar b ON f.id = b.foydalanuvchi_id
JOIN kategoriyalar k ON b.kategoriya_id = k.id
WHERE b.summa > 100000;
Ko'p JOIN ko'p emas — to'g'ri ishlatilsa tez ishlaydi. Muammo ko'pincha index yo'qligida.
Tez-tez uchraydigan xatolar
ON sharti o'rniga WHERE ishlatish:
-- ❌ — bu INNER JOIN kabi ishlaydi, LEFT JOIN natijasi yo'q
SELECT f.ism, b.mahsulot
FROM foydalanuvchilar f, buyurtmalar b
WHERE f.id = b.foydalanuvchi_id;
-- ✅ — aniq JOIN sintaksisi
SELECT f.ism, b.mahsulot
FROM foydalanuvchilar f
LEFT JOIN buyurtmalar b ON f.id = b.foydalanuvchi_id;
Vergul bilan yozish eski uslub — tushunarsiz va xatoga moyil.
LEFT JOIN da NULL tekshirishni unutish:
-- ❌ — WHERE ga qo'shilgan shart LEFT JOIN ni INNER JOIN ga aylantiradi
SELECT f.ism, b.summa
FROM foydalanuvchilar f
LEFT JOIN buyurtmalar b ON f.id = b.foydalanuvchi_id
WHERE b.summa > 100000; -- ← NULL > 100000 = false → Soli yo'qoladi
-- ✅ — NULL ni ham hisobga olish
WHERE b.summa > 100000 OR b.summa IS NULL;
Ustun nomi to'qnashuvi:
-- ❌ — qaysi jadvalning "id" si?
SELECT id, ism, mahsulot FROM foydalanuvchilar JOIN buyurtmalar ON ...;
-- ✅ — alias bilan aniq
SELECT f.id, f.ism, b.mahsulot FROM foydalanuvchilar f JOIN buyurtmalar b ON ...;
Ikki jadvalda bir xil ustun nomi bo'lsa — alias ishlatmaslik xatoga olib keladi.
Xulosa
| JOIN turi | Natija |
|---|---|
| INNER JOIN | Faqat ikkala jadvalda mos yozuv bor qatorlar |
| LEFT JOIN | Chap jadval to'liq, o'ngda yo'q bo'lsa NULL |
| RIGHT JOIN | O'ng jadval to'liq, chapda yo'q bo'lsa NULL |
| FULL JOIN | Ikkalasi to'liq, mos kelmaganlarda NULL |
| CROSS JOIN | Barcha kombinatsiyalar (ON sharti yo'q) |
| SELF JOIN | Jadval o'zi bilan — ierarxik ma'lumotlar uchun |
Amalda eng ko'p ishlatiladigani: INNER JOIN va LEFT JOIN. LEFT JOIN + WHERE o'ng.id IS NULL — "birovda yo'q narsani topish" uchun kuchli pattern.
Keyingi dars
13-dars: One-to-Many — loyihalash va so'rovlar