INNER, LEFT, RIGHT, FULL, CROSS, SELF JOIN

~20 daq · PostgreSQL · JOIN va Munosabatlar

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