CREATE TABLE — constraints, PRIMARY KEY, FOREIGN KEY, CHECK
Foydalanuvchilar jadvalini yaratyapsiz. Quyidagi holatlar bo'lmasligi kerak:
- Ikki foydalanuvchi bir xil email bilan ro'yxatdan o'tishi
- Email bo'sh qolishi
- Yosh manfiy son bo'lishi
- Buyurtmada mavjud bo'lmagan foydalanuvchi ko'rsatilishi
Bularni ilovaning kodida tekshirish mumkin. Lekin bu yetarli emas — boshqa dasturchi yangi API yozsa va tekshiruvni unutsa, yoki ma'lumot to'g'ridan-to'g'ri database ga kiritilsa — noto'g'ri ma'lumot o'tib ketadi.
Bu qoidalar database darajasida belgilanishi kerak. Shunda qaysi dastur, qaysi til orqali kiritmasin — qoida buzilmaydi. Buning uchun constraint lar ishlatiladi.
Constraint nima?
Constraint — jadvalga qo'yiladigan qoida. Shu qoidaga uymagan ma'lumot database tomonidan rad etiladi, xato qaytariladi.
Hayotiy o'xshatma
Pasport olish uchun ariza to'ldirish. Ariza blankasida qoidalar bor: seriya raqami bo'lishi shart, har pasportning raqami noyob bo'lishi kerak, tug'ilgan sana bo'lishi kerak. Qoida buzilsa — ariza qabul qilinmaydi. Constraint lar — jadvalning "ariza blankas qoidalari".
Jadval yaratish
CREATE TABLE foydalanuvchilar (
id SERIAL PRIMARY KEY,
ism TEXT NOT NULL,
email TEXT NOT NULL UNIQUE,
yosh INTEGER CHECK (yosh >= 0),
rol TEXT DEFAULT 'user',
yaratilgan TIMESTAMPTZ DEFAULT NOW()
);
Har bir qator: ustun nomi → tur → constraint. Endi har bir constraint ni alohida ko'rib chiqamiz.
PRIMARY KEY — har qatorning noyob belgisi
Jadvalda minglab qator bo'ladi. Ularning har birini qanday farqlaymiz? Buning uchun har qatorga noyob identifikator kerak — PRIMARY KEY.
PRIMARY KEY ikki qoidani birdan ta'minlaydi: bo'sh bo'lmaydi (NOT NULL) va takrorlanmaydi (UNIQUE). Har jadvalda faqat bitta PRIMARY KEY bo'lishi mumkin.
SERIAL — PRIMARY KEY bilan juft ishlatiladi. Yangi qator qo'shilganda qiymat o'zi oshib boradi: 1, 2, 3...
CREATE TABLE mahsulotlar (
id SERIAL PRIMARY KEY, -- ← 1, 2, 3 ... o'zi oshadi
nom TEXT NOT NULL
);
Ba'zida bitta ustun yetarli emas — ikki ustun birgalikda noyob bo'lishi kerak. Masalan, bir buyurtmada bir mahsulot faqat bir marta bo'lishi kerak:
CREATE TABLE buyurtma_tarkibi (
buyurtma_id INTEGER,
mahsulot_id INTEGER,
miqdor INTEGER NOT NULL,
PRIMARY KEY (buyurtma_id, mahsulot_id) -- ← juft birgalikda noyob
);
NOT NULL — majburiy maydon
Ustundagi qiymat bo'sh (NULL) qolmasligi kerak bo'lganda NOT NULL yoziladi.
Qaysi maydonlar majburiy? Ism, email, telefon — bo'sh bo'lmaydi. Bio, manzil, rasm — ixtiyoriy, bo'sh qolishi mumkin.
CREATE TABLE foydalanuvchilar (
id SERIAL PRIMARY KEY,
ism TEXT NOT NULL, -- ← majburiy
email TEXT NOT NULL, -- ← majburiy
bio TEXT -- ← ixtiyoriy, NULL bo'lishi mumkin
);
Email ko'rsatilmay foydalanuvchi qo'shilmoqchi bo'lsa — database rad etadi:
INSERT INTO foydalanuvchilar (ism) VALUES ('Vali');
-- ERROR: null value in column "email" violates not-null constraint
UNIQUE — takrorlanmasin
Bir xil email bilan ikki foydalanuvchi bo'lmasligi kerak. Buning uchun UNIQUE — bu ustundagi har bir qiymat jadvalda faqat bir marta bo'lishi mumkin.
CREATE TABLE foydalanuvchilar (
id SERIAL PRIMARY KEY,
email TEXT NOT NULL UNIQUE, -- ← takrorlanmaydi
telefon TEXT UNIQUE -- ← ixtiyoriy, lekin kiritilsa noyob bo'lishi shart
);
Bir xil email ikkinchi marta kiritilsa:
INSERT INTO foydalanuvchilar (email) VALUES ('ali@mail.com'); -- ✓
INSERT INTO foydalanuvchilar (email) VALUES ('ali@mail.com');
-- ERROR: duplicate key value violates unique constraint
DEFAULT — standart qiymat
Har yangi foydalanuvchi ro'yxatdan o'tganda roli 'user' bo'ladi. Har safar bu qiymatni yozib o'tirmaslik uchun DEFAULT ishlatiladi — qiymat kiritilmasa, database o'zi standart qiymatni qo'yadi.
CREATE TABLE foydalanuvchilar (
id SERIAL PRIMARY KEY,
ism TEXT NOT NULL,
rol TEXT DEFAULT 'user', -- ← kiritilmasa 'user'
faol BOOLEAN DEFAULT TRUE, -- ← kiritilmasa true
yaratilgan TIMESTAMPTZ DEFAULT NOW() -- ← kiritilmasa hozirgi vaqt
);
Faqat ism kiritildi — qolganlari o'zi to'ldirildi:
INSERT INTO foydalanuvchilar (ism) VALUES ('Ali');
SELECT * FROM foydalanuvchilar WHERE ism = 'Ali';
-- id | ism | rol | faol | yaratilgan
-- ----+-------+-------+------+----------------------
-- 1 | Ali | user | t | 2024-03-15 14:30:00
CHECK — o'z qoidangiz
Ba'zan standart constraintlar yetmaydi — o'zingiz qoida belgilashingiz kerak. Yosh manfiy bo'lmasligi, narx noldan katta bo'lishi, chegirma 0 dan 100 gacha bo'lishi. Buning uchun CHECK.
CREATE TABLE foydalanuvchilar (
id SERIAL PRIMARY KEY,
ism TEXT NOT NULL,
yosh INTEGER CHECK (yosh >= 0 AND yosh <= 150)
);
INSERT INTO foydalanuvchilar (ism, yosh) VALUES ('Ali', -5);
-- ERROR: new row violates check constraint "foydalanuvchilar_yosh_check"
Ikki ustunni birgalikda tekshirish ham mumkin. Masalan, aksiya tugash sanasi boshlanish sanasidan keyin bo'lishi kerak:
CREATE TABLE aksiyalar (
id SERIAL PRIMARY KEY,
boshlanish DATE NOT NULL,
tugash DATE NOT NULL,
CHECK (tugash > boshlanish) -- ← jadval darajasida, ikkala ustun birgalikda
);
FOREIGN KEY — jadvallar orasidagi bog'liq
Buyurtma biror foydalanuvchiga tegishli. Lekin database bu bog'liqni o'zi bilmaydi — aytib qo'ymasangiz, mavjud bo'lmagan foydalanuvchiga ham buyurtma qo'shilishi mumkin.
FOREIGN KEY — "bu ustundagi qiymat boshqa jadvaldagi ustunda mavjud bo'lishi shart" degan qoida. Bu ikki jadvalni bog'laydi va ma'lumotlar izchilligini ta'minlaydi.
CREATE TABLE foydalanuvchilar (
id SERIAL PRIMARY KEY,
ism TEXT NOT NULL
);
CREATE TABLE buyurtmalar (
id SERIAL PRIMARY KEY,
foydalanuvchi_id INTEGER NOT NULL REFERENCES foydalanuvchilar(id),
-- ↑ foydalanuvchilar.id da bor bo'lishi shart
miqdor NUMERIC(10, 2) NOT NULL,
sana TIMESTAMPTZ DEFAULT NOW()
);
Mavjud bo'lmagan foydalanuvchiga buyurtma qo'shilmoqchi bo'lsa:
INSERT INTO buyurtmalar (foydalanuvchi_id, miqdor) VALUES (999, 50000);
-- ERROR: insert or update on table "buyurtmalar" violates foreign key constraint
-- Detail: Key (foydalanuvchi_id)=(999) is not present in table "foydalanuvchilar".
ON DELETE — ota jadval o'chirilganda nima bo'ladi?
Ali o'chirilmoqchi. Lekin uning buyurtmalari bor. Bu holda nima bo'lishi kerak? Uch xil strategiya mavjud — qaysi biri to'g'ri ekanligi loyihaga bog'liq:
RESTRICT — standart. Ali o'chirilmaydi, avval buyurtmalarini o'chirish kerak. Xavfsiz, lekin qo'lda tartib kerak.
CASCADE — Ali o'chirilsa, uning barcha buyurtmalari ham avtomatik o'chadi. Qulay, lekin ehtiyot bo'lish kerak — tasodifan o'chirib yubormaslik uchun.
SET NULL — Ali o'chirilsa, buyurtmalardagi foydalanuvchi_id NULL ga o'zgaradi. Buyurtmalar saqlanib qoladi, lekin kimnikiligi noma'lum bo'ladi. Arxiv maqsadida foydali.
CREATE TABLE buyurtmalar (
id SERIAL PRIMARY KEY,
foydalanuvchi_id INTEGER REFERENCES foydalanuvchilar(id) ON DELETE CASCADE,
miqdor NUMERIC(10, 2) NOT NULL
);
psql da ko'rish
\l — databaselar ro'yxati
\c mydb — databasega kirish
\dt — jadvallar ro'yxati
\d foydalanuvchilar — jadval tuzilmasi (ustunlar, constraint lar)
\q — chiqish
Tez-tez uchraydigan xatolar
FOREIGN KEY uchun avval ota jadval yaratilishi kerak
buyurtmalar jadvali foydalanuvchilar ga murojaat qiladi. Lekin foydalanuvchilar hali yaratilmagan bo'lsa — xato chiqadi. Avval "ota" jadval yaratiladi:
-- ❌ foydalanuvchilar yo'q
CREATE TABLE buyurtmalar (
foydalanuvchi_id INTEGER REFERENCES foydalanuvchilar(id)
);
-- ✅ avval ota jadval, keyin bola
CREATE TABLE foydalanuvchilar (id SERIAL PRIMARY KEY, ism TEXT);
CREATE TABLE buyurtmalar (foydalanuvchi_id INTEGER REFERENCES foydalanuvchilar(id));
FOREIGN KEY bor jadval o'chirilmaydi
foydalanuvchilar o'chirilmoqchi, lekin buyurtmalar unga bog'liq. Database "avval bog'liq narsalarni yo'q qiling" deydi:
DROP TABLE foydalanuvchilar;
-- ERROR: cannot drop table because other objects depend on it
-- ✅ avval bola jadval
DROP TABLE buyurtmalar;
DROP TABLE foydalanuvchilar;
NULL va UNIQUE birga ishlashi
UNIQUE constraint NULL qiymatlarni bir-biridan farqli deb hisoblaydi. Ya'ni bir nechta NULL bo'lishi mumkin — bu ba'zilarni ajablantiradi:
CREATE TABLE test (telefon TEXT UNIQUE);
INSERT INTO test VALUES (NULL); -- ✓
INSERT INTO test VALUES (NULL); -- ✓ ham — NULL lar "bir xil" hisoblanmaydi
INSERT INTO test VALUES ('+998901234567'); -- ✓
INSERT INTO test VALUES ('+998901234567'); -- ❌ qiymat takrorlandi
Xulosa
Constraint — database darajasidagi qoida. Buzilsa — ma'lumot qabul qilinmaydi.
PRIMARY KEY — har qatorning noyob belgisi, bo'sh bo'lmaydi
NOT NULL — majburiy maydon, bo'sh qolmaydi
UNIQUE — takrorlanmaydi
DEFAULT — qiymat kiritilmasa standart ishlatiladi
CHECK — o'zingiz belgilagan qoida
FOREIGN KEY — boshqa jadval bilan bog'liq, izchillikni ta'minlaydi
Constraint lar ilovadan mustaqil — qaysi dastur yoki til orqali kiritmasin, qoida buzilmaydi.
Keyingi dars
7-dars: ALTER TABLE, DROP — ustun qo'shish, o'zgartirish, o'chirish