11-bo‘lim

JOIN - jadvallarni birlashtirish

INNER, LEFT, RIGHT va CROSS JOIN, bir nechta jadvalni birlashtirish, o'ziga JOIN va JOIN + GROUP BY.

🕑 13 daqiqa o‘qish 📄 693 so‘z 👁 7 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. INNER JOIN - eng ko'p ishlatiladigan
  2. JOIN turlari
  3. LEFT JOIN - juda muhim
  4. Bog'liq yozuvi yo'qlarni topish
  5. ON va WHERE farqi
  6. Bir nechta jadvalni birlashtirish
  7. JOIN + GROUP BY
  8. O'ziga JOIN (self join)
  9. CROSS JOIN
  10. UNION - natijalarni birlashtirish
  11. Amaliy misollar
  12. JOIN va tezlik
  13. Xulosa

Ma'lumot bir nechta jadvalga bo'lingan. JOIN ularni birgalikda o'qish imkonini beradi.

INNER JOIN - eng ko'p ishlatiladigan #

SQL
SELECT
    t.ism,
    t.familiya,
    g.nomi AS guruh
FROM talabalar t
INNER JOIN guruhlar g ON g.id = t.guruh_id;
Natija
+----------+----------+--------+
| ism      | familiya | guruh  |
+----------+----------+--------+
| Husanboy | Qodirov  | IT-101 |
| Sardor   | Aliyev   | IT-101 |
| Aziza    | Tosheva  | IT-101 |
| Malika   | Yusupova | IT-102 |
| Bekzod   | Rasulov  | IT-102 |
+----------+----------+--------+

INNER so'zini tushirib qoldirish mumkin - JOIN o'zi INNER JOIN degani.

JOIN turlari #

A B INNER JOIN Faqat mos kelganlar A B LEFT JOIN A dagi hammasi + mos B A B RIGHT JOIN B dagi hammasi + mos A FULL OUTER JOIN Hammasi (MySQL da yo'q) LEFT JOIN + IS NULL Faqat A da bor, B da yo'q
Ko'k rang natijada qaytadigan qatorlarni bildiradi
TuriNima qaytaradi
INNER JOINFaqat ikkala jadvalda mos kelgan qatorlar
LEFT JOINChap jadvaldagi barcha + mos kelgan o'ng
RIGHT JOINO'ng jadvaldagi barcha + mos kelgan chap
CROSS JOINBarcha kombinatsiyalar (dekart ko'paytmasi)

LEFT JOIN - juda muhim #

SQL
-- Barcha guruhlar, hatto talabasi bo'lmagani ham
SELECT
    g.nomi AS guruh,
    t.ism,
    t.familiya
FROM guruhlar g
LEFT JOIN talabalar t ON t.guruh_id = g.id;
Natija
+---------+----------+----------+
| guruh   | ism      | familiya |
+---------+----------+----------+
| IT-101  | Husanboy | Qodirov  |
| IT-101  | Sardor   | Aliyev   |
| IT-102  | Malika   | Yusupova |
| IT-201  | Nodira   | Sobirova |
| DIZ-101 | NULL     | NULL     |    <- talabasi yo'q
+---------+----------+----------+

INNER JOIN bo'lganda DIZ-101 umuman ko'rinmasdi.

LEFT JOIN qachon kerak?

"Barcha X lar va ularning Y lari (agar bo'lsa)" degan savolga javob berish uchun:

  • Barcha mahsulotlar va ularning sharhlari
  • Barcha foydalanuvchilar va ularning oxirgi buyurtmasi
  • Barcha kategoriyalar va ulardagi mahsulotlar soni

Agar "bo'lmasa ham ko'rsat" kerak bo'lsa - LEFT JOIN.

Bog'liq yozuvi yo'qlarni topish #

SQL
-- Talabasi bo'lmagan guruhlar
SELECT g.nomi
FROM guruhlar g
LEFT JOIN talabalar t ON t.guruh_id = g.id
WHERE t.id IS NULL;
Natija
+---------+
| nomi    |
+---------+
| DIZ-101 |
+---------+
SQL
-- Hech qachon buyurtma bermagan mijozlar
SELECT m.ism, m.email
FROM mijozlar m
LEFT JOIN buyurtmalar b ON b.mijoz_id = m.id
WHERE b.id IS NULL;
Bu naqsh juda ko'p ishlatiladi

LEFT JOIN ... WHERE o'ng_jadval.id IS NULL = "chap jadvalda bor, lekin o'ng jadvalda yo'q". "Yetim yozuvlar", "faol bo'lmagan mijozlar", "sotilmagan mahsulotlar" kabi savollarning standart yechimi.

ON va WHERE farqi #

LEFT JOIN da shartni to'g'ri joyga qo'ying
SQL
-- 1: shart ON da - LEFT JOIN saqlanadi
SELECT g.nomi, COUNT(t.id) AS soni
FROM guruhlar g
LEFT JOIN talabalar t ON t.guruh_id = g.id AND t.faolmi = TRUE
GROUP BY g.id;
-- Natija: BARCHA guruhlar, faol talabalar soni bilan (0 bo'lsa ham)

-- 2: shart WHERE da - LEFT JOIN INNER JOIN ga aylanadi!
SELECT g.nomi, COUNT(t.id) AS soni
FROM guruhlar g
LEFT JOIN talabalar t ON t.guruh_id = g.id
WHERE t.faolmi = TRUE
GROUP BY g.id;
-- Natija: faqat faol talabasi BOR guruhlar

Sabab: WHERE JOIN dan keyin ishlaydi va NULL qatorlarni tashlab yuboradi.

Qoida: o'ng jadvalga tegishli shart ON da, chap jadvalga tegishlisi WHERE da.

Bir nechta jadvalni birlashtirish #

SQL
SELECT
    m.ism                AS mijoz,
    b.id                 AS buyurtma,
    mh.nomi              AS mahsulot,
    be.soni,
    be.narx,
    be.soni * be.narx    AS jami,
    k.nomi               AS kategoriya
FROM buyurtmalar b
JOIN mijozlar m              ON m.id  = b.mijoz_id
JOIN buyurtma_elementlari be ON be.buyurtma_id = b.id
JOIN mahsulotlar mh          ON mh.id = be.mahsulot_id
JOIN kategoriyalar k         ON k.id  = mh.kategoriya_id
WHERE b.holat = 'tolangan'
ORDER BY b.yaratilgan DESC;
Uzun JOIN larni o'qishli yozish
  1. Har bir JOIN ni yangi satrga
  2. ON shartlarini tekislang
  3. Jadval taxalluslari qisqa va ma'noli bo'lsin
  4. ON da har doim o'ng.id = chap.ustun tartibida yozing

Bu 5 jadvalli so'rovni ham o'qish mumkin qiladi.

JOIN + GROUP BY #

Eng kuchli kombinatsiya - hisobotlar shundan iborat:

SQL
-- Har bir guruhdagi talabalar soni va o'rtacha bahosi
SELECT
    g.nomi                          AS guruh,
    COUNT(t.id)                     AS talabalar,
    ROUND(AVG(t.ortacha_baho), 2)   AS ortacha,
    MAX(t.ortacha_baho)             AS eng_yuqori
FROM guruhlar g
LEFT JOIN talabalar t ON t.guruh_id = g.id
GROUP BY g.id, g.nomi
ORDER BY ortacha DESC;
Natija
+---------+-----------+---------+------------+
| guruh   | talabalar | ortacha | eng_yuqori |
+---------+-----------+---------+------------+
| IT-102  |         2 |    4.05 |       4.90 |
| IT-101  |         3 |    4.17 |       4.60 |
| IT-201  |         2 |    3.90 |       4.30 |
| DIZ-101 |         0 |    NULL |       NULL |
+---------+-----------+---------+------------+
SQL
-- Eng ko'p sotilgan mahsulotlar
SELECT
    mh.nomi,
    SUM(be.soni)                AS sotilgan,
    SUM(be.soni * be.narx)      AS tushum,
    COUNT(DISTINCT b.mijoz_id)  AS mijozlar
FROM mahsulotlar mh
JOIN buyurtma_elementlari be ON be.mahsulot_id = mh.id
JOIN buyurtmalar b           ON b.id = be.buyurtma_id
WHERE b.holat IN ('tolangan', 'yetkazildi')
GROUP BY mh.id, mh.nomi
ORDER BY tushum DESC
LIMIT 10;
COUNT(*) va LEFT JOIN
SQL
-- XATO: talabasi yo'q guruhda ham 1 chiqadi
SELECT g.nomi, COUNT(*) FROM guruhlar g
LEFT JOIN talabalar t ON t.guruh_id = g.id
GROUP BY g.id;

-- TO'G'RI: NULL sanalmaydi
SELECT g.nomi, COUNT(t.id) FROM guruhlar g
LEFT JOIN talabalar t ON t.guruh_id = g.id
GROUP BY g.id;

COUNT(*) qatorlarni sanaydi (NULL qator ham bitta qator). COUNT(t.id) esa NULL bo'lmagan qiymatlarni sanaydi.

O'ziga JOIN (self join) #

Bir jadvalni o'zi bilan birlashtirish:

SQL
CREATE TABLE xodimlar (
    id        INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    ism       VARCHAR(120) NOT NULL,
    lavozim   VARCHAR(80),
    rahbar_id INT UNSIGNED NULL,

    FOREIGN KEY (rahbar_id) REFERENCES xodimlar (id) ON DELETE SET NULL
) ENGINE=InnoDB;

INSERT INTO xodimlar (ism, lavozim, rahbar_id) VALUES
    ('Aziz Karimov',    'Direktor',       NULL),
    ('Dilnoza Yusupova','Bo''lim boshlig''i', 1),
    ('Sardor Aliyev',   'Dasturchi',      2),
    ('Malika Tosheva',  'Dasturchi',      2);

-- Har bir xodim va uning rahbari
SELECT
    x.ism      AS xodim,
    x.lavozim,
    r.ism      AS rahbar
FROM xodimlar x
LEFT JOIN xodimlar r ON r.id = x.rahbar_id;
Natija
+-------------------+-------------------+-------------------+
| xodim             | lavozim           | rahbar            |
+-------------------+-------------------+-------------------+
| Aziz Karimov      | Direktor          | NULL              |
| Dilnoza Yusupova  | Bo'lim boshlig'i  | Aziz Karimov      |
| Sardor Aliyev     | Dasturchi         | Dilnoza Yusupova  |
| Malika Tosheva    | Dasturchi         | Dilnoza Yusupova  |
+-------------------+-------------------+-------------------+

CROSS JOIN #

Barcha kombinatsiyalar:

SQL
-- Har bir o'lcham va rang kombinatsiyasi
SELECT o.nomi AS olcham, r.nomi AS rang
FROM olchamlar o
CROSS JOIN ranglar r;
CROSS JOIN ni tasodifan yozib qo'yish
SQL
-- ON shartisiz JOIN - bu CROSS JOIN
SELECT * FROM talabalar, guruhlar;

1000 ta talaba × 50 ta guruh = 50 000 qator. Katta jadvallarda bu serverni bloklaydi.

Har doim JOIN ... ON ... shaklida yozing. Eski FROM a, b WHERE sintaksisidan qoching.

UNION - natijalarni birlashtirish #

JOIN ustunlarni, UNION esa qatorlarni birlashtiradi:

SQL
SELECT ism, 'talaba' AS turi FROM talabalar
UNION
SELECT ism, 'o''qituvchi' FROM oqituvchilar
ORDER BY ism;

-- Takrorlarni ham qoldirish (tezroq)
SELECT shahar FROM talabalar
UNION ALL
SELECT shahar FROM oqituvchilar;
UNIONUNION ALL
TakrorlarO'chiriladiQoladi
TezlikSekinroqTezroq
Takrorlar bo'lmasligiga ishonchingiz komil bo'lsa

UNION ALL ishlating - u saralash va takrorlarni tekshirish bosqichini o'tkazib yuboradi.

Amaliy misollar #

SQL
-- 1. Har bir talabaning fanlari va baholari
SELECT
    CONCAT(t.ism, ' ', t.familiya) AS talaba,
    f.nomi                          AS fan,
    tf.baho
FROM talabalar t
JOIN talaba_fan tf ON tf.talaba_id = t.id
JOIN fanlar f      ON f.id = tf.fan_id
ORDER BY talaba, fan;

-- 2. Hech qanday fan olmagan talabalar
SELECT t.ism, t.familiya
FROM talabalar t
LEFT JOIN talaba_fan tf ON tf.talaba_id = t.id
WHERE tf.talaba_id IS NULL;

-- 3. Har bir fan bo'yicha statistika
SELECT
    f.nomi                    AS fan,
    COUNT(tf.talaba_id)       AS talabalar,
    ROUND(AVG(tf.baho), 2)    AS ortacha_baho,
    SUM(tf.baho >= 4)         AS yaxshi_baholar
FROM fanlar f
LEFT JOIN talaba_fan tf ON tf.fan_id = f.id
GROUP BY f.id, f.nomi
ORDER BY ortacha_baho DESC;

-- 4. Mijozlar va ularning buyurtmalari summasi
SELECT
    m.ism,
    m.email,
    COUNT(DISTINCT b.id)                  AS buyurtmalar,
    IFNULL(SUM(be.soni * be.narx), 0)     AS jami_xarid,
    MAX(b.yaratilgan)                     AS oxirgi_buyurtma
FROM mijozlar m
LEFT JOIN buyurtmalar b           ON b.mijoz_id = m.id AND b.holat <> 'bekor'
LEFT JOIN buyurtma_elementlari be ON be.buyurtma_id = b.id
GROUP BY m.id, m.ism, m.email
ORDER BY jami_xarid DESC;

JOIN va tezlik #

JOIN ustunlariga indeks qo'ying
SQL
-- Tashqi kalit ustuniga indeks MAJBURIY
CREATE INDEX idx_guruh ON talabalar (guruh_id);

Indekssiz JOIN da baza har bir chap qator uchun butun o'ng jadvalni skanerlaydi. 1000 × 1000 = million amal.

Indeks bilan esa har bir qidiruv O(log n) bo'ladi.

MySQL da FOREIGN KEY yaratilganda indeks avtomatik qo'shiladi, lekin oddiy JOIN ustunlarida buni qo'lda qilish kerak.

Amaliy topshiriq

kutubxona bazasida:

  1. Barcha kitoblar va ularning mualliflarini JOIN bilan chiqaring.
  2. LEFT JOIN bilan barcha mualliflarni ko'rsating - kitobi yo'qlari ham.
  3. Hech qanday kitobi bo'lmagan mualliflarni toping (IS NULL).
  4. Har bir muallifning nechta kitobi borligini JOIN + GROUP BY bilan sanang.
  5. ijaralar jadvalini qo'shib, kim qaysi kitobni olganini ko'rsating (3 jadval).
  6. Hech qachon ijaraga olinmagan kitoblarni toping.
  7. ON va WHERE da shart qo'yish farqini sinab ko'ring.
  8. JOIN ustunlariga indeks qo'shing va EXPLAIN bilan farqni ko'ring.

Xulosa #

  • INNER JOIN faqat mos kelgan qatorlarni, LEFT JOIN chap jadvaldagi hammasini qaytaradi.
  • LEFT JOIN ... WHERE o'ng.id IS NULL - "bog'liq yozuvi yo'qlarni topish" naqshi.
  • LEFT JOIN da o'ng jadval sharti ON da bo'lishi kerak, WHERE da emas.
  • COUNT(*) o'rniga COUNT(o'ng_jadval.id) ishlating.
  • O'ziga JOIN ierarxiya (rahbar-xodim, kategoriya-ichki kategoriya) uchun.
  • ON shartisiz JOIN - bu CROSS JOIN, ehtiyot bo'ling.
  • JOIN ustunlariga indeks majburiy - aks holda so'rov juda sekin ishlaydi.
  • UNION qatorlarni birlashtiradi; takror kerak bo'lmasa UNION ALL tezroq.

Keyingi bo'limda ichki so'rovlarni o'rganamiz.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.