UNION, INTERSECT, EXCEPT
Muammodan boshlaylik
Ikki alohida jadvalda ma'lumot bor: faol_mijozlar va arxiv_mijozlar. Barchasini birga ko'rsatish kerak — bitta ro'yxatda. JOIN ishlamaydi, chunki bir-biriga bog'liq emas, shunchaki bir xil tuzilmadagi ikki jadval.
Yoki boshqa holat: yangi ro'yxatdan eski ro'yxatda ham bor bo'lganlarni topish kerak. Yoki aksincha — yangida bor, eskida yo'q.
Bu uchala muammo uchun — to'plam operatorlari: UNION, INTERSECT, EXCEPT.
To'plam operatorlari nima?
To'plam operatorlari ikki so'rovning natijalarini birlashtiradi, kesishini yoki farqini topadi. Matematikadagi to'plamlar nazariyasiga o'xshash.
A = {1, 2, 3, 4}
B = {3, 4, 5, 6}
UNION = {1, 2, 3, 4, 5, 6} ← ikkalasini birlashtir
INTERSECT = {3, 4} ← faqat ikkalasida borlar
EXCEPT = {1, 2} ← A da bor, B da yo'q
Vizual:
A B UNION
┌───┐ ┌───┐ ┌───────┐
│1,2│ 3,4│ │ → │1,2,3,4│
│ ├─────┤5,6│ │ 5,6 │
└───┘ └───┘ └───────┘
INTERSECT EXCEPT (A - B)
┌───┐ ┌───┐
│3,4│ │1,2│
└───┘ └───┘
Shartlar
To'plam operatorlari ishlashi uchun ikki so'rov:
- Bir xil ustunlar soni bo'lishi kerak
- Ustunlar turlari mos kelishi kerak
- Natijada ustun nomlari birinchi so'rovdan olinadi
Namuna jadvallar
CREATE TABLE eski_mijozlar (
ism TEXT,
email TEXT
);
CREATE TABLE yangi_mijozlar (
ism TEXT,
email TEXT
);
INSERT INTO eski_mijozlar VALUES
('Ali', 'ali@mail.com'),
('Vali', 'vali@mail.com'),
('Soli', 'soli@mail.com');
INSERT INTO yangi_mijozlar VALUES
('Soli', 'soli@mail.com'),
('Kamol', 'kamol@mail.com'),
('Jasur', 'jasur@mail.com');
UNION — birlashtirish
Ikki so'rov natijasini birlashtiradi. Takroriy qatorlarni avtomatik o'chiradi.
SELECT ism, email FROM eski_mijozlar
UNION
SELECT ism, email FROM yangi_mijozlar;
ism │ email
--------+----------------
Ali │ ali@mail.com
Vali │ vali@mail.com
Soli │ soli@mail.com ← ikkala jadvalda bor, lekin bir marta chiqdi
Kamol │ kamol@mail.com
Jasur │ jasur@mail.com
Soli ikki jadvalda ham bor — lekin UNION takrorni o'chirdi, bir marta chiqdi.
UNION ALL — takrorlarni saqlab qoldirish
Agar takrorlar kerak bo'lsa yoki tezroq ishlashi kerak bo'lsa:
SELECT ism, email FROM eski_mijozlar
UNION ALL
SELECT ism, email FROM yangi_mijozlar;
ism │ email
--------+----------------
Ali │ ali@mail.com
Vali │ vali@mail.com
Soli │ soli@mail.com
Soli │ soli@mail.com ← ikki marta chiqdi
Kamol │ kamol@mail.com
Jasur │ jasur@mail.com
UNION takrorlarni o'chirish uchun barcha qatorlarni solishtiradi — bu sekinroq. UNION ALL shunchaki qatorlarni qo'shib ketadi — tezroq. Takror bo'lmasligini bilsangiz — UNION ALL ishlating.
INTERSECT — kesishma
Faqat ikkala so'rovda ham bor qatorlarni qaytaradi.
SELECT ism, email FROM eski_mijozlar
INTERSECT
SELECT ism, email FROM yangi_mijozlar;
ism │ email
-------+---------------
Soli │ soli@mail.com
Faqat Soli ikkala jadvalda ham bor. Ali va Vali faqat eskida, Kamol va Jasur faqat yangida.
Amalda ishlatilishi: ikki ro'yxatda ham borlarni topish — masalan, ikkala kampaniyaga ham yozilgan foydalanuvchilar.
EXCEPT — farq
Birinchi so'rovda bor, lekin ikkinchisida yo'q qatorlarni qaytaradi.
-- Eski mijozlar, yangilarda yo'qlar
SELECT ism, email FROM eski_mijozlar
EXCEPT
SELECT ism, email FROM yangi_mijozlar;
ism │ email
-------+---------------
Ali │ ali@mail.com
Vali │ vali@mail.com
Ali va Vali faqat eski jadvalda bor. Soli ikkisida ham bor — EXCEPT uni o'chirdi.
Tartib muhim: A EXCEPT B ≠ B EXCEPT A.
-- Yangi mijozlar, eskilarda yo'qlar
SELECT ism, email FROM yangi_mijozlar
EXCEPT
SELECT ism, email FROM eski_mijozlar;
ism │ email
--------+----------------
Kamol │ kamol@mail.com
Jasur │ jasur@mail.com
Amaliy misol — turli jadvallarni birlashtirish
Hisobot uchun barcha moliya operatsiyalarini bitta ro'yxatda ko'rsatish:
SELECT 'Kirim' AS tur, sana, summa FROM kirimlar
UNION ALL
SELECT 'Chiqim', sana, summa FROM chiqimlar
ORDER BY sana;
Bu yerda birinchi so'rovda 'Kirim' — qo'lda qo'shilgan ustun. Natijada har bir qatorda operatsiya turi ko'rinadi.
ORDER BY va LIMIT
To'plam operatori bilan ORDER BY va LIMIT faqat eng oxirida — butun natijaga qo'llanadi:
SELECT ism FROM eski_mijozlar
UNION
SELECT ism FROM yangi_mijozlar
ORDER BY ism -- ← butun natijani tartiblaydi
LIMIT 3; -- ← butun natijadan faqat 3 ta
Har bir qism so'rovga alohida ORDER BY qo'yib bo'lmaydi — mantiqsiz, chunki natijalar birlashtirilib ketadi.
Tez-tez uchraydigan xatolar
Ustunlar soni mos kelmasa:
-- ❌ — birinchida 2 ustun, ikkinchida 3
SELECT ism, email FROM eski_mijozlar
UNION
SELECT ism, email, telefon FROM yangi_mijozlar;
-- ERROR: each UNION query must have the same number of columns
Ustunlar soni har ikki so'rovda bir xil bo'lishi shart. Agar biridagisi kam bo'lsa — NULL bilan to'ldirish:
SELECT ism, email, NULL AS telefon FROM eski_mijozlar
UNION
SELECT ism, email, telefon FROM yangi_mijozlar;
UNION o'rniga UNION ALL ishlatish kerak bo'lganda:
-- ❌ — takrorlar kerak bo'lgan holda UNION ishlatildi
-- Natijada ba'zi qatorlar yo'qoldi, raqam noto'g'ri chiqdi
SELECT mahsulot FROM bugungi_buyurtmalar
UNION
SELECT mahsulot FROM kechagi_buyurtmalar;
-- ✅ — barcha qatorlar kerak, takror bo'lsa ham
SELECT mahsulot FROM bugungi_buyurtmalar
UNION ALL
SELECT mahsulot FROM kechagi_buyurtmalar;
Hisobotlarda UNION ishlatib, takroriy qatorlar o'chirilsa — natijalar noto'g'ri bo'lib qoladi. Takrorlar kerakmi yo'qmi — avval o'ylab ko'ring.
Xulosa
To'plam operatorlari ikki so'rov natijasini birlashtiradi — jadvallarni emas, natijalarni.
UNION → ikkalasini birlashtir, takrorlarni o'chir
UNION ALL → ikkalasini birlashtir, tezroq, takrorlar saqlanadi
INTERSECT → faqat ikkalasida borlar
EXCEPT → birinchida bor, ikkinchisida yo'q
Shartlar: bir xil ustunlar soni, mos turlar. Ustun nomlari birinchi so'rovdan.
ORDER BY va LIMIT — faqat eng oxirida, butun natijaga.
Keyingi dars
21-dars: LATERAL JOIN — nima, qachon kerak