Constraints — PRIMARY KEY, NOT NULL, UNIQUE, DEFAULT, CHECK

~20 daq · MySQL · DDL — Tuzilma Boshqarish

Muammodan boshlaylik

Saytingizda ro'yxatdan o'tish formasi bor. PHP kodida tekshiruvlar yozilgan: email bo'sh emas, takrorlanmaydi, yosh musbat. Lekin:

  • Admin panel boshqa dasturchi tomonidan yozilgan — u tekshiruvni unutgan
  • Mobil ilova API orqali to'g'ridan-to'g'ri yozadi — u yerda boshqa qoidalar
  • Kimdir Workbench da qo'lda INSERT qildi
  • Ikki foydalanuvchi bir soniyada bir xil email bilan ro'yxatdan o'tdi — ikkala PHP so'rov ham "email bo'sh" deb tekshirdi

Natijada bazada: bo'sh emaillar, dublikat akkauntlar, -5 yoshli foydalanuvchilar.

Cheklovlar — qoidalarni bazaning o'zida belgilash. Ma'lumot qaysi yo'l bilan kelishidan qat'i nazar — baza noto'g'ri ma'lumotni qabul qilmaydi. Bu oxirgi va eng ishonchli himoya chizig'i.


NOT NULL — majburiy maydon

CREATE TABLE mijozlar (
    id     INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    ism    VARCHAR(100) NOT NULL,
    email  VARCHAR(255) NOT NULL,
    telefon VARCHAR(20) NULL          -- ixtiyoriy
);

INSERT INTO mijozlar (ism) VALUES ('Aziz');
-- ERROR 1364: Field 'email' doesn't have a default value

Qoida: har bir ustunni avval NOT NULL deb tasavvur qiling. Faqat "bu ma'lumot haqiqatan ham bo'lmasligi mumkin" bo'lsa — NULL.

[!WARNING] NOT NULL bo'sh matnni ('') to'xtatmaydi. '' — bu NULL emas, uzunligi nol bo'lgan matn. Bo'sh matnni ham taqiqlash uchun — CHECK (pastda).


UNIQUE — takrorlanmas qiymat

CREATE TABLE mijozlar (
    id     INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    email  VARCHAR(255) NOT NULL UNIQUE,
    telefon VARCHAR(20) NULL UNIQUE
);

INSERT INTO mijozlar (email) VALUES ('aziz@mail.uz');
INSERT INTO mijozlar (email) VALUES ('aziz@mail.uz');
-- ERROR 1062: Duplicate entry 'aziz@mail.uz' for key 'mijozlar.email'

Ikki bir vaqtdagi so'rov muammosi ham hal: baza ikkinchisini albatta rad etadi. Ilovada 1062 xatosini ushlab, "bu email band" deb ko'rsatasiz (PHP kursi, 38-dars).

UNIQUE ustunda NULL lar bir nechta bo'lishi mumkin — chunki NULL "noma'lum", ikki noma'lum teng emas. Telefonsiz 100 ta mijoz — muammo emas.

Bir nechta ustun bo'yicha

CREATE TABLE baholar (
    talaba_id INT UNSIGNED NOT NULL,
    fan_id    INT UNSIGNED NOT NULL,
    ball      TINYINT UNSIGNED NOT NULL,
    UNIQUE (talaba_id, fan_id)      -- bitta talaba bitta fandan bitta baho
);

Alohida-alohida takrorlanishi mumkin, lekin juftlik noyob.


PRIMARY KEY

Primary key = NOT NULL + UNIQUE + jadvalda faqat bitta.

id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY

Murakkab (composite) primary key — bir nechta ustundan:

CREATE TABLE mahsulot_teglar (
    mahsulot_id INT UNSIGNED NOT NULL,
    teg_id      INT UNSIGNED NOT NULL,
    PRIMARY KEY (mahsulot_id, teg_id)
);

Bunday jadvallar ko'p-ko'p munosabatda ishlatiladi (19-dars).


DEFAULT — standart qiymat

CREATE TABLE buyurtmalar (
    id          INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    holat       VARCHAR(20) NOT NULL DEFAULT 'yangi',
    chegirma    TINYINT UNSIGNED NOT NULL DEFAULT 0,
    yaratilgan  DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    yangilangan DATETIME NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
    kod         CHAR(36) NOT NULL DEFAULT (UUID())
);

INSERT INTO buyurtmalar () VALUES ();
SELECT * FROM buyurtmalar;
-- holat = 'yangi', chegirma = 0, yaratilgan = hozirgi vaqt, kod = '3f2a...'
  • DEFAULT CURRENT_TIMESTAMP — yaratilgan vaqt avtomatik
  • ON UPDATE CURRENT_TIMESTAMP — qator har o'zgarganda vaqt yangilanadi
  • DEFAULT (ifoda) — MySQL 8.0.13+ da qavs ichida funksiya ham mumkin

CHECK — ixtiyoriy qoida (MySQL 8.0.16+)

CREATE TABLE mahsulotlar (
    id      INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    nom     VARCHAR(200) NOT NULL,
    narx    INT UNSIGNED NOT NULL,
    chegirmali_narx INT UNSIGNED NULL,
    reyting TINYINT UNSIGNED NULL,

    CONSTRAINT chk_nom_bosh_emas  CHECK (TRIM(nom) <> ''),
    CONSTRAINT chk_reyting        CHECK (reyting BETWEEN 1 AND 5),
    CONSTRAINT chk_chegirma       CHECK (chegirmali_narx IS NULL OR chegirmali_narx < narx)
);

INSERT INTO mahsulotlar (nom, narx, reyting) VALUES ('Telefon', 1000, 7);
-- ERROR 3819: Check constraint 'chk_reyting' is violated.

INSERT INTO mahsulotlar (nom, narx, chegirmali_narx) VALUES ('Telefon', 1000, 1500);
-- ERROR 3819: Check constraint 'chk_chegirma' is violated.

CONSTRAINT nom — cheklovga nom berish. Xato xabarida aynan qaysi qoida buzilgani ko'rinadi va keyinchalik uni nomi bo'yicha o'chirish oson.

Bir nechta ustunni bog'laydigan qoidalar (chegirma < narx) — faqat CHECK bilan.

[!WARNING] MySQL 8.0.16 dan oldingi versiyalarda CHECK sintaksisi qabul qilinardi, lekin e'tiborsiz qoldirilardi. Eski versiyada bo'lsangiz — qoida ishlamaydi va hech qanday ogohlantirish yo'q. SELECT VERSION(); bilan tekshiring.


Cheklovlarni ko'rish

SELECT CONSTRAINT_NAME, CONSTRAINT_TYPE
FROM information_schema.TABLE_CONSTRAINTS
WHERE TABLE_SCHEMA = 'dokon' AND TABLE_NAME = 'mahsulotlar';
+-------------------+-----------------+
| CONSTRAINT_NAME   | CONSTRAINT_TYPE |
+-------------------+-----------------+
| PRIMARY           | PRIMARY KEY     |
| chk_chegirma      | CHECK           |
| chk_nom_bosh_emas | CHECK           |
| chk_reyting       | CHECK           |
+-------------------+-----------------+

information_schema — MySQL ning o'zi haqidagi ma'lumotlar bazasi: barcha jadvallar, ustunlar, indekslar shu yerda.


SQL mode — qat'iylik darajasi

SELECT @@sql_mode;
-- ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION

STRICT_TRANS_TABLES — noto'g'ri qiymat kelsa xato beradi. Busiz MySQL jimgina "tuzatadi": 300 belgilik matnni 200 ga qisqartiradi, 'abc' ni 0 ga aylantiradi — faqat ogohlantirish bilan.

Eski loyihalar va ba'zi hostinglar strict mode ni o'chirib qo'yadi. O'chirmang — jimgina buzilgan ma'lumot xatodan ancha yomon.


Nima uchun shunday?

Nima uchun tekshiruvni ilovada ham, bazada ham qilish kerak — takrorlash emasmi?

Ular turli vazifani bajaradi. Ilovadagi tekshiruv — foydalanuvchi uchun: tushunarli xabar, qaysi maydonda xato, formani qayta to'ldirmaslik. Bazadagi cheklov — ma'lumot uchun: qaysi ilova, qaysi dasturchi, qaysi xato bilan yozmasin — buzilgan ma'lumot kirmaydi. Ilovalar keladi va ketadi (veb sayt, mobil ilova, admin panel, import skripti). Ma'lumot esa qoladi.


Xulosa

Eslab qoling:

  • NOT NULL — majburiy; '' ni to'xtatmaydi
  • UNIQUE — takrorlanmas; NULL lar bir nechta bo'lishi mumkin; bir nechta ustun bo'yicha ham
  • PRIMARY KEY — NOT NULL + UNIQUE, jadvalda bitta
  • DEFAULT — standart qiymat; CURRENT_TIMESTAMP, ON UPDATE
  • CHECK — ixtiyoriy qoida (8.0.16+); CONSTRAINT nom bilan nomlang
  • Strict SQL mode ni o'chirmang
  • Bazadagi cheklov — oxirgi himoya chizig'i

Keyingi dars

7-dars: FOREIGN KEY — CASCADE, SET NULL, RESTRICT