7-bo‘lim

Ikkinchi normal shakl (2NF)

Funksional bog'liqlik, kompozit kalitga qisman bog'liqlik, 2NF buzilishini aniqlash va jadvalni bo'lish.

🕑 16 daqiqa o‘qish 📄 763 so‘z 👁 1 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Funksional bog'liqlik
  2. 2NF buzilgan jadval
  3. Qisman bog'liqlikni aniqlash
  4. Anomaliyalar
  5. 2NF ga keltirish
  6. Anomaliyalar yo'qoldi
  7. Amaliy tekshirish usuli
  8. Qachon bo'lmaslik kerak
  9. Xulosa

1NF bajarilgach, keyingi savol tug'iladi: har bir ustun butun kalitga bog'liqmi, yoki uning bir qismiga?

Funksional bog'liqlik #

Funksional bog'liqlik: A -> B A ni bilsangiz, B ni ANIQ bilasiz Bir xil A qiymatida B doim bir xil bo'ladi Bog'liqlik bor talaba_id -> ism fan_id -> fan_nomi pasport -> tugilgan_sana Bog'liqlik yo'q ism -> talaba_id shahar -> telefon tugilgan_yil -> ism
Normalizatsiya - funksional bog'liqliklarni to'g'ri joyga qo'yish

2NF buzilgan jadval #

SQL
CREATE TABLE yozilishlar_yomon (
    talaba_id     INT NOT NULL,
    fan_id        INT NOT NULL,
    talaba_ismi   VARCHAR(100) NOT NULL,
    talaba_sinfi  VARCHAR(10)  NOT NULL,
    fan_nomi      VARCHAR(50)  NOT NULL,
    fan_krediti   TINYINT      NOT NULL,
    baho          TINYINT,
    PRIMARY KEY (talaba_id, fan_id)
);

INSERT INTO yozilishlar_yomon VALUES
    (1, 1, 'Husanboy', '9-A', 'Matematika',  6, 5),
    (1, 2, 'Husanboy', '9-A', 'Fizika',      4, 4),
    (1, 3, 'Husanboy', '9-A', 'Ingliz tili', 3, 5),
    (2, 1, 'Malika',   '9-A', 'Matematika',  6, 4),
    (2, 2, 'Malika',   '9-A', 'Fizika',      4, 5),
    (3, 1, 'Kamola',   '9-B', 'Matematika',  6, 3);
SQL
SELECT talaba_id, fan_id, talaba_ismi, fan_nomi, baho
FROM yozilishlar_yomon
ORDER BY talaba_id, fan_id;
Natija
+-----------+--------+-------------+-------------+------+
| talaba_id | fan_id | talaba_ismi | fan_nomi    | baho |
+-----------+--------+-------------+-------------+------+
|         1 |      1 | Husanboy    | Matematika  |    5 |
|         1 |      2 | Husanboy    | Fizika      |    4 |
|         1 |      3 | Husanboy    | Ingliz tili |    5 |
|         2 |      1 | Malika      | Matematika  |    4 |
|         2 |      2 | Malika      | Fizika      |    5 |
|         3 |      1 | Kamola      | Matematika  |    3 |
+-----------+--------+-------------+-------------+------+

Jadval 1NF da - har katakda bitta qiymat. Lekin muammo ko'rinib turibdi: Husanboy uch marta, Matematika uch marta takrorlangan.

Qisman bog'liqlikni aniqlash #

Birlamchi kalit - (talaba_id, fan_id). Har ustun uchun savol beramiz: kalitning qaysi qismiga bog'liq?

UstunNimaga bog'liqHolat
talaba_ismiFaqat talaba_idQisman
talaba_sinfiFaqat talaba_idQisman
fan_nomiFaqat fan_idQisman
fan_kreditiFaqat fan_idQisman
bahoIkkalasigaTo'liq
SQL
-- Isbot: bir xil talaba_id da ism DOIM bir xil
SELECT talaba_id, COUNT(DISTINCT talaba_ismi) AS turli_ismlar
FROM yozilishlar_yomon
GROUP BY talaba_id
ORDER BY talaba_id;
Natija
+-----------+--------------+
| talaba_id | turli_ismlar |
+-----------+--------------+
|         1 |            1 |
|         2 |            1 |
|         3 |            1 |
+-----------+--------------+
SQL
-- Baho esa faqat juftlikka bog'liq - bir talabada turli baholar bor
SELECT talaba_id, COUNT(DISTINCT baho) AS turli_baholar
FROM yozilishlar_yomon
GROUP BY talaba_id
ORDER BY talaba_id;
Natija
+-----------+---------------+
| talaba_id | turli_baholar |
+-----------+---------------+
|         1 |             2 |
|         2 |             2 |
|         3 |             1 |
+-----------+---------------+
2NF ta'rifi

Jadval 2NF da bo'ladi, agar u 1NF da bo'lsa va har bir kalitga kirmaydigan ustun butun birlamchi kalitga to'liq bog'liq bo'lsa.

Boshqacha aytganda: kalitning bir qismi yetarli bo'lgan ustun bo'lmasligi kerak.

Muhim natija: agar birlamchi kalit bitta ustundan iborat bo'lsa, jadval avtomatik 2NF da bo'ladi - qisman bog'liqlik jismonan mumkin emas.

Shuning uchun 2NF muammosi faqat kompozit kalitli jadvallarda uchraydi. Sun'iy id ishlatilganda bu muammo ko'pincha o'z-o'zidan yo'qoladi - lekin yashiringan holda qolishi ham mumkin (quyidagi ogohlantirishga qarang).

Anomaliyalar #

SQL
-- 1. Yangilash anomaliyasi: ismni bir joyda o'zgartirdik
UPDATE yozilishlar_yomon
SET talaba_ismi = 'Husanboy Qodirov'
WHERE talaba_id = 1 AND fan_id = 1;

SELECT talaba_id, COUNT(DISTINCT talaba_ismi) AS turli_ismlar
FROM yozilishlar_yomon
WHERE talaba_id = 1
GROUP BY talaba_id;
Natija
+-----------+--------------+
| talaba_id | turli_ismlar |
+-----------+--------------+
|         1 |            2 |
+-----------+--------------+
SQL
-- 2. O'chirish anomaliyasi: Kamolaning yagona bahosini o'chirsak,
--    uning ismi va sinfi ham yo'qoladi
DELETE FROM yozilishlar_yomon WHERE talaba_id = 3;

SELECT COUNT(*) AS kamola_haqida_malumot
FROM yozilishlar_yomon
WHERE talaba_ismi = 'Kamola';
Natija
+-----------------------+
| kamola_haqida_malumot |
+-----------------------+
|                     0 |
+-----------------------+
SQL
-- 3. Qo'shish anomaliyasi: hali hech kim yozilmagan fanni
--    qo'shib bo'lmaydi - talaba_id kerak
INSERT INTO yozilishlar_yomon (fan_id, fan_nomi, fan_krediti)
VALUES (4, 'Tarix', 2);
Natija
ERROR 1364 (HY000): Field 'talaba_id' doesn't have a default value

2NF ga keltirish #

Qisman bog'liqliklarni ajratamiz yozilishlar_yomon talaba_id, fan_id, talaba_ismi, talaba_sinfi, fan_nomi, fan_krediti, baho talabalar id (PK) ism sinf yozilishlar talaba_id (PK, FK) fan_id (PK, FK) baho fanlar id (PK) nom kredit
Kalitning har qismi o'z jadvalini oladi, juftlikka bog'liq ustun qoladi
SQL
CREATE TABLE talabalar (
    id   INT PRIMARY KEY AUTO_INCREMENT,
    ism  VARCHAR(100) NOT NULL,
    sinf VARCHAR(10)  NOT NULL
);

CREATE TABLE fanlar (
    id     INT PRIMARY KEY AUTO_INCREMENT,
    nom    VARCHAR(50) NOT NULL UNIQUE,
    kredit TINYINT NOT NULL
);

CREATE TABLE yozilishlar (
    talaba_id INT NOT NULL,
    fan_id    INT NOT NULL,
    baho      TINYINT,
    PRIMARY KEY (talaba_id, fan_id),
    FOREIGN KEY (talaba_id) REFERENCES talabalar(id),
    FOREIGN KEY (fan_id)    REFERENCES fanlar(id)
);

INSERT INTO talabalar (ism, sinf) VALUES
    ('Husanboy', '9-A'), ('Malika', '9-A'), ('Kamola', '9-B');

INSERT INTO fanlar (nom, kredit) VALUES
    ('Matematika', 6), ('Fizika', 4), ('Ingliz tili', 3);

INSERT INTO yozilishlar VALUES
    (1, 1, 5), (1, 2, 4), (1, 3, 5),
    (2, 1, 4), (2, 2, 5),
    (3, 1, 3);

Xuddi shu ma'lumot, endi uch jadvalda:

SQL
SELECT t.ism, f.nom AS fan, y.baho
FROM yozilishlar y
JOIN talabalar t ON t.id = y.talaba_id
JOIN fanlar f    ON f.id = y.fan_id
ORDER BY y.talaba_id, y.fan_id;
Natija
+----------+-------------+------+
| ism      | fan         | baho |
+----------+-------------+------+
| Husanboy | Matematika  |    5 |
| Husanboy | Fizika      |    4 |
| Husanboy | Ingliz tili |    5 |
| Malika   | Matematika  |    4 |
| Malika   | Fizika      |    5 |
| Kamola   | Matematika  |    3 |
+----------+-------------+------+

Anomaliyalar yo'qoldi #

SQL
-- 1. Ismni o'zgartirish - bitta qator, ziddiyat mumkin emas
UPDATE talabalar SET ism = 'Husanboy Qodirov' WHERE id = 1;

SELECT ism FROM talabalar WHERE id = 1;
Natija
+------------------+
| ism              |
+------------------+
| Husanboy Qodirov |
+------------------+
SQL
-- 2. Barcha bahoni o'chirsak ham talaba qoladi
DELETE FROM yozilishlar WHERE talaba_id = 3;

SELECT ism, sinf FROM talabalar WHERE id = 3;
Natija
+--------+------+
| ism    | sinf |
+--------+------+
| Kamola | 9-B  |
+--------+------+
SQL
-- 3. Hali hech kim yozilmagan fanni qo'shish mumkin
INSERT INTO fanlar (nom, kredit) VALUES ('Tarix', 2);

SELECT f.nom, COUNT(y.talaba_id) AS yozilganlar
FROM fanlar f
LEFT JOIN yozilishlar y ON y.fan_id = f.id
GROUP BY f.id, f.nom
ORDER BY f.id;
Natija
+-------------+-------------+
| nom         | yozilganlar |
+-------------+-------------+
| Matematika  |           3 |
| Fizika      |           2 |
| Ingliz tili |           1 |
| Tarix       |           0 |
+-------------+-------------+

Uchala anomaliya ham yo'qoldi.

Sun'iy id 2NF muammosini yashiradi

Ko'p dasturchi bog'lovchi jadvalga sun'iy kalit qo'yadi:

SQL
CREATE TABLE yozilishlar_yashirin (
    id           INT PRIMARY KEY AUTO_INCREMENT,   -- sun'iy kalit
    talaba_id    INT NOT NULL,
    fan_id       INT NOT NULL,
    talaba_ismi  VARCHAR(100),                     -- hali ham takrorlanadi!
    fan_nomi     VARCHAR(50),                      -- bu ham
    baho         TINYINT
);

Rasmiy jihatdan bu jadval 2NF da - birlamchi kalit bitta ustun, shuning uchun qisman bog'liqlik "yo'q".

Lekin muammo qolgan: talaba_ismi hamon takrorlanadi va yangilash anomaliyasi hamon mumkin.

Normal shakllar matematik ta'riflar - ular sxemani mexanik tekshiradi. Ular sog'lom fikrni almashtirmaydi.

To'g'ri savol har doim bir xil:

Bu ustun shu jadvalning mavzusiga tegishlimi?

yozilishlar jadvalining mavzusi - yozilish. Talabaning ismi unga tegishli emas, u talabaga tegishli.

Shuning uchun UNIQUE (talaba_id, fan_id) qo'yib, mantiqiy kalitni tiklang - shunda normal shakllar yana ish beradi.

Amaliy tekshirish usuli #

SQL
-- Takrorlanish darajasini o'lchash
SELECT
    COUNT(*) AS qatorlar,
    COUNT(DISTINCT talaba_id) AS noyob_talaba,
    COUNT(DISTINCT fan_id) AS noyob_fan
FROM yozilishlar;
Natija
+----------+--------------+-----------+
| qatorlar | noyob_talaba | noyob_fan |
+----------+--------------+-----------+
|        6 |            3 |         3 |
+----------+--------------+-----------+
2NF buzilishini tez aniqlash

Kompozit kalitli jadvalni ko'rganingizda, har kalitga kirmaydigan ustun uchun so'rang:

"Bu qiymat kalitning bir qismi bilan aniqlanadimi?"

Amaliy belgilar:

BelgiMisol
Ustun nomida boshqa jadval nomitalaba_ismi, fan_nomi
Bir ustunni bilsangiz, boshqasini bilasizfan_idfan_nomi
COUNT(DISTINCT) 1 ga tengYuqoridagi tekshiruv

SQL bilan tekshirish:

SQL
SELECT talaba_id
FROM yozilishlar_yomon
GROUP BY talaba_id
HAVING COUNT(DISTINCT talaba_ismi) > 1;

Natija bo'sh bo'lsa - talaba_id → talaba_ismi bog'liqligi bor, ya'ni 2NF buzilgan (kalit kompozit bo'lsa).

Diqqat: bu tekshiruv mavjud ma'lumotga asoslanadi. Ma'lumot kam bo'lsa, tasodifan bog'liqlik ko'rinishi mumkin. Yakuniy qaror biznes qoidasi bo'yicha qabul qilinadi.

Qachon bo'lmaslik kerak #

Tarixiy ma'lumotni ataylab takrorlash

Bitta muhim istisno bor - vaqt bo'yicha o'zgaradigan qiymatlar.

SQL
CREATE TABLE buyurtma_qatorlari (
    buyurtma_id INT NOT NULL,
    mahsulot_id INT NOT NULL,
    soni        INT NOT NULL,
    narx        DECIMAL(10,2) NOT NULL,   -- ATAYLAB takrorlangan
    PRIMARY KEY (buyurtma_id, mahsulot_id)
);

narx mahsulot_id ga bog'liqdek ko'rinadi - ya'ni 2NF buzilgan.

Lekin bu xato emas: bu sotilgan paytdagi narx. Mahsulot narxi ertaga o'zgarsa, eski buyurtmalar o'zgarmasligi kerak.

SQL
mahsulotlar.narx           -- BUGUNGI narx
buyurtma_qatorlari.narx    -- SOTILGAN paytdagi narx

Bular turli faktlar, shuning uchun takrorlanish emas.

Xuddi shunday misollar:

UstunNima uchun nusxalanadi
Buyurtmadagi narxNarx o'zgaradi, tarix qoladi
Shartnomadagi manzilKo'chib ketishi mumkin
Hisobotdagi kursO'sha kundagi kurs

Belgi: qiymat "o'sha paytdagi holat" bo'lsa - nusxalash to'g'ri. Bu 9-bo'limdagi denormalizatsiyaning eng asosli turi.

Amaliy topshiriq
  1. Kompozit kalitli jadval yaratib, ma'lumot kiriting.
  2. Har ustun kalitning qaysi qismiga bog'liqligini aniqlang.
  3. COUNT(DISTINCT) bilan bog'liqlikni isbotlang.
  4. Ismni bir joyda o'zgartirib, ziddiyat hosil qiling.
  5. Yagona qatorni o'chirib, ma'lumot yo'qolishini ko'ring.
  6. Yozilmagan fanni qo'shishga urinib ko'ring.
  7. Jadvalni uchga bo'lib, 2NF ga keltiring.
  8. Uchala anomaliya yo'qolganini tekshiring.
  9. Sun'iy id muammoni qanday yashirishini tushuntiring.
  10. Buyurtmadagi narx nima uchun takrorlanishi kerakligini ayting.

Xulosa #

  • Funksional bog'liqlik: A ni bilsangiz, B ni aniq bilasiz.
  • 2NF: har ustun butun kalitga bog'liq bo'lishi kerak.
  • Muammo faqat kompozit kalitli jadvallarda bo'ladi.
  • Bitta ustunli kalitda jadval avtomatik 2NF da.
  • Qisman bog'liqlik uchala anomaliyani keltirib chiqaradi.
  • Yechim: kalitning har qismiga o'z jadvali.
  • Sun'iy id muammoni yashiradi, hal qilmaydi.
  • UNIQUE (a, b) bilan mantiqiy kalitni tiklang.
  • To'g'ri savol: ustun jadvalning mavzusiga tegishlimi?
  • Tarixiy qiymat (sotilgan narx) - ataylab nusxalanadi.

Keyingi bo'limda uchinchi normal shakl va BCNF ni ko'ramiz.

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.