One-to-One — qachon kerak
Muammodan boshlaylik
Foydalanuvchilar tizimi yozyapsiz. Har bir foydalanuvchining profil ma'lumotlari bor: rasm, bio, tug'ilgan kun, ijtimoiy tarmoq linklari. Bularni foydalanuvchilar jadvaliga qo'shish mumkin — lekin jadval 20-30 ustunli bo'lib ketadi.
Bundan tashqari, ba'zi foydalanuvchilar profilni to'ldirmasligi mumkin — unda ko'p ustun NULL bo'lib turadi.
Yechim: profil ma'lumotlarini alohida jadvalga ko'chirish. Bir foydalanuvchi — bitta profil. Bu — One-to-One.
One-to-One nima?
One-to-One — birinchi jadvaldagi har bir yozuv ikkinchi jadvaldagi faqat bitta yozuvga bog'liq, va ikkinchi jadvaldagi har bir yozuv ham birinchi jadvaldagi faqat bitta yozuvga bog'liq bo'lgan munosabat.
Hayotiy o'xshatma: pasport va fuqaro. Har bir fuqaroning faqat bitta pasporti bor. Har bir pasport faqat bitta fuqaroga tegishli. Biri boshqasini takrorlamaydi.
foydalanuvchilar profillar
───────────────── ──────────────────────
id │ email id │ foydalanuvchi_id │ bio │ rasm
───┼────────── ───┼──────────────────┼─────┼──────
1 │ ali@mail.com 1 │ 1 │ ... │ ...
2 │ vali@mail.com 2 │ 2 │ ... │ ...
3 │ soli@mail.com
↑ ↑
bitta bitta
Nima uchun alohida jadval?
Hammani bitta jadvalga yozsa ham bo'lmaydimi? Ba'zan bo'ladi. Lekin ajratish quyidagi hollarda mantiqiy:
Ma'lumotlar ixtiyoriy bo'lganda. Har bir foydalanuvchi profil to'ldirmaydi. Alohida jadval bo'lsa — profilsiz foydalanuvchi uchun hech qanday NULL ustun yo'q, shunchaki profillar jadvalida yozuv yo'q.
Jadval juda katta bo'lib ketganda. Asosiy jadvalda faqat tez-tez ishlatiladigan ustunlar qoladi. Kamroq ishlatiladigan katta ma'lumotlar (bio, sozlamalar, konfiguratsiya) alohida jadvala — so'rovlar tezroq ishlaydi.
Xavfsizlik bo'lganda. Masalan, foydalanuvchilar jadvalida parol hash, bank karta ma'lumotlari saqlanmaydi — ular alohida jadvalga chiqariladi. Ilovaning turli qismlari turli jadvalga murojaat qiladi.
Qanday loyihalanadi?
One-to-One da ikkinchi jadvalga foreign key qo'yiladi — lekin u UNIQUE bo'lishi shart. UNIQUE bo'lmasa One-to-Many bo'lib ketadi.
CREATE TABLE foydalanuvchilar (
id SERIAL PRIMARY KEY,
email TEXT UNIQUE NOT NULL,
parol TEXT NOT NULL
);
CREATE TABLE profillar (
id SERIAL PRIMARY KEY,
foydalanuvchi_id INT UNIQUE NOT NULL REFERENCES foydalanuvchilar(id) ON DELETE CASCADE,
-- ↑ UNIQUE — bitta foydalanuvchiga faqat bitta profil
ism TEXT,
bio TEXT,
rasm_url TEXT,
tug_ilgan_kun DATE
);
UNIQUE NOT NULL REFERENCES — bu uch kalit so'z birgalikda One-to-One ni kafolatlaydi:
REFERENCES— bog'lanish borUNIQUE— ikkinchi profildan himoyaNOT NULL— har bir profilning foydalanuvchisi bo'lishi shart
Ma'lumot qo'shish
INSERT INTO foydalanuvchilar (email, parol) VALUES
('ali@mail.com', 'hash1'),
('vali@mail.com', 'hash2');
-- Profil ixtiyoriy — Soli hali to'ldirmagan
INSERT INTO profillar (foydalanuvchi_id, ism, bio) VALUES
(1, 'Ali Karimov', 'Dasturchi'),
(2, 'Vali Rahimov', 'Dizayner');
-- ❌ — bir foydalanuvchiga ikkinchi profil — xato
INSERT INTO profillar (foydalanuvchi_id, ism) VALUES (1, 'Boshqa profil');
-- ERROR: duplicate key value violates unique constraint
So'rovlar
Foydalanuvchi bilan profil birga
SELECT
f.email,
p.ism,
p.bio
FROM foydalanuvchilar f
LEFT JOIN profillar p ON f.id = p.foydalanuvchi_id
WHERE f.id = 1;
LEFT JOIN — profil to'ldirilmagan foydalanuvchilar ham ko'rinadi, faqat profil ustunlari NULL bo'ladi.
Hali profil to'ldirmagan foydalanuvchilar
SELECT f.email
FROM foydalanuvchilar f
LEFT JOIN profillar p ON f.id = p.foydalanuvchi_id
WHERE p.id IS NULL;
Foreign key qaysi tomonda bo'ladi?
One-to-One da foreign key ikki tomonga ham qo'yish mumkin. Qaysi tomonga qo'yish mantiqan to'g'riroq?
Qoida: ixtiyoriy tomonga qo'yiladi.
foydalanuvchi ←────────── profil
(har doim bor) foydalanuvchi (ixtiyoriy)
_id
Foydalanuvchi har doim mavjud, profil ixtiyoriy. Shu sababli profillar jadvaliga foreign key qo'yildi. Agar foydalanuvchilar jadvaliga profil_id qo'ysak — har bir foydalanuvchi yaratilganda darhol profil ham yaratish majburiy bo'ladi. Bu noqulay.
Munosabatlarni solishtirish
Uchala munosabatni birga ko'rish:
One-to-One
──────────
Foydalanuvchi 1 ←──► Profil 1
Foydalanuvchi 2 ←──► Profil 2
One-to-Many
───────────
Foydalanuvchi 1 ◄──┬── Buyurtma 1
├── Buyurtma 2
└── Buyurtma 3
Foydalanuvchi 2 ◄──── Buyurtma 4
Many-to-Many
────────────
Talaba 1 ──┬──► Kurs A
└──► Kurs B
Talaba 2 ──┬──► Kurs A
└──► Kurs C
Loyihalashda munosabat turini aniqlash uchun ikki savolga javob bering:
- "Bitta A uchun nechta B bo'lishi mumkin?" → bir yoki ko'p?
- "Bitta B uchun nechta A bo'lishi mumkin?" → bir yoki ko'p?
| A uchun B | B uchun A | Munosabat |
|---|---|---|
| Bir | Bir | One-to-One |
| Ko'p | Bir | One-to-Many |
| Ko'p | Ko'p | Many-to-Many |
Tez-tez uchraydigan xatolar
UNIQUE ni unutish:
-- ❌ — UNIQUE yo'q — bu One-to-Many ga aylanadi
foydalanuvchi_id INT NOT NULL REFERENCES foydalanuvchilar(id)
-- ✅ — UNIQUE bor — One-to-One kafolat
foydalanuvchi_id INT UNIQUE NOT NULL REFERENCES foydalanuvchilar(id)
UNIQUE yo'q bo'lsa — bir foydalanuvchiga ikki profil qo'shish mumkin. Munosabat buziladi.
Hammani bitta jadvalga solish:
Agar jadvalda 30 dan ortiq ustun bo'lsa — bu signal. Ehtimol, ba'zi ustunlarni alohida jadvalga chiqarish vaqti kelgan. Katta jadvalda har bir SELECT * ko'p ma'lumot tortib keladi — kerak bo'lmagan ustunlar ham.
Xulosa
One-to-One — bitta yozuvga bitta yozuv. Pasport va fuqaro kabi.
Qachon kerak:
- Asosiy jadval juda katta bo'lib ketganda — katta/ixtiyoriy ma'lumotlarni ajratish
- Xavfsizlik — maxfiy ma'lumotlarni alohida jadvalda saqlash
- Profil, sozlamalar, konfiguratsiya kabi ixtiyoriy tuzilmalar
Kalit qoida: Foreign key qo'yilgan jadvalga UNIQUE — o'sha UNIQUE One-to-Many dan One-to-One ni ajratib turadi.
Keyingi dars
16-dars: Subquery — WHERE, FROM, SELECT ichida, EXISTS