Что такое вторая нормальная форма в БД?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Что такое вторая нормальная форма (2NF) в БД?
Вторая нормальная форма (2NF) — это принцип организации данных в реляционной базе данных, который предотвращает частичные зависимости. Другими словами, все неключевые атрибуты должны полностью зависеть от первичного ключа, а не от его части.
Иерархия нормальных форм
1NF (Первая нормальная форма)
↓
2NF (Вторая нормальная форма)
↓
3NF (Третья нормальная форма)
↓
BCNF (Boyce-Codd нормальная форма)
Каждая следующая форма включает требования предыдущих.
Предварительные требования для 2NF
1. Таблица должна быть в 1NF (Первая нормальная форма):
-- ❌ НЕ в 1NF: есть несоставные атрибуты
CREATE TABLE Students (
id INT PRIMARY KEY,
name VARCHAR(100),
skills TEXT -- "Java, Python, C++" — это список!
);
-- ✅ В 1NF: все атрибуты атомарные (неделимые)
CREATE TABLE Students (
id INT PRIMARY KEY,
name VARCHAR(100),
skill VARCHAR(50) -- Один скилл на строку
);
Определение 2NF
2NF требует:
- Таблица должна быть в 1NF
- Все неключевые атрибуты должны полностью зависеть от первичного ключа
- Нет частичных зависимостей от составного первичного ключа
Полная зависимость: атрибут зависит от ВСЕХ компонентов составного ключа
Частичная зависимость: атрибут зависит от ЧАСТИ составного ключа ← НАРУШЕНИЕ 2NF
Пример 1: Нарушение 2NF (Плохо)
-- ❌ НЕ в 2NF: есть частичная зависимость
CREATE TABLE StudentCourses (
student_id INT,
course_id INT,
student_name VARCHAR(100), -- Зависит ТОЛЬКО от student_id!
course_name VARCHAR(100), -- Зависит ТОЛЬКО от course_id!
grade CHAR(1), -- Зависит от ОБОИХ (student_id, course_id)
PRIMARY KEY (student_id, course_id)
);
-- Данные:
-- student_id | course_id | student_name | course_name | grade
-- 1 | 101 | "Alice" | "Java" | A
-- 1 | 102 | "Alice" | "Python" | B
-- 2 | 101 | "Bob" | "Java" | C
-- Проблема:
-- - student_name зависит только от student_id (ЧАСТИЧНАЯ зависимость)
-- - course_name зависит только от course_id (ЧАСТИЧНАЯ зависимость)
-- Это нарушение 2NF!
Пример 2: Исправление в 2NF (Хорошо)
-- ✅ В 2NF: разделили на три таблицы
-- Таблица студентов
CREATE TABLE Students (
student_id INT PRIMARY KEY,
student_name VARCHAR(100)
);
-- Таблица курсов
CREATE TABLE Courses (
course_id INT PRIMARY KEY,
course_name VARCHAR(100)
);
-- Таблица связей (студент-курс)
CREATE TABLE StudentCourses (
student_id INT,
course_id INT,
grade CHAR(1),
PRIMARY KEY (student_id, course_id),
FOREIGN KEY (student_id) REFERENCES Students(student_id),
FOREIGN KEY (course_id) REFERENCES Courses(course_id)
);
-- Теперь:
-- - StudentCourses таблица содержит ТОЛЬКО данные, зависящие от обоих ключей
-- - grade зависит от ОБОИХ (student_id И course_id) ✅
-- - Нет частичных зависимостей ✅
Пример 3: Заказ с товарами (Нарушение 2NF)
-- ❌ НЕ в 2NF
CREATE TABLE OrderItems (
order_id INT,
product_id INT,
product_name VARCHAR(100), -- Зависит только от product_id!
product_price DECIMAL(10, 2), -- Зависит только от product_id!
quantity INT, -- Зависит от обоих
total DECIMAL(10, 2), -- Зависит от обоих
PRIMARY KEY (order_id, product_id)
);
-- Данные:
-- order_id | product_id | product_name | product_price | quantity | total
-- 1 | 101 | "Ноутбук" | 1000.00 | 1 | 1000.00
-- 1 | 102 | "Мышка" | 20.00 | 2 | 40.00
-- 2 | 101 | "Ноутбук" | 1000.00 | 3 | 3000.00
-- Проблемы:
-- 1. product_name повторяется (аномалия обновления)
-- 2. Если удалить заказ 1, потеряем информацию о товаре
-- 3. Нарушена целостность данных
Пример 4: Исправление в 2NF (Правильно)
-- ✅ В 2NF
CREATE TABLE Products (
product_id INT PRIMARY KEY,
product_name VARCHAR(100),
product_price DECIMAL(10, 2)
);
CREATE TABLE Orders (
order_id INT PRIMARY KEY,
order_date DATE,
customer_id INT
);
CREATE TABLE OrderItems (
order_id INT,
product_id INT,
quantity INT,
total DECIMAL(10, 2),
PRIMARY KEY (order_id, product_id),
FOREIGN KEY (order_id) REFERENCES Orders(order_id),
FOREIGN KEY (product_id) REFERENCES Products(product_id)
);
-- Теперь:
-- - Каждый факт хранится в одном месте
-- - Нет дублирования
-- - Нет частичных зависимостей
Пример 5: Сотрудники и Отделения (Нарушение)
-- ❌ НЕ в 2NF
CREATE TABLE Employees (
employee_id INT,
project_id INT,
employee_name VARCHAR(100), -- Зависит только от employee_id!
department_name VARCHAR(100), -- Зависит только от employee_id!
salary DECIMAL(10, 2), -- Зависит только от employee_id!
project_hours INT, -- Зависит от ОБОИХ
PRIMARY KEY (employee_id, project_id)
);
-- Данные:
-- employee_id | project_id | employee_name | department_name | salary | project_hours
-- 1 | 101 | "Alice" | "IT" | 5000 | 40
-- 1 | 102 | "Alice" | "IT" | 5000 | 30
-- 2 | 101 | "Bob" | "HR" | 4000 | 20
-- Проблемы - дублирование данных!
Пример 6: Исправление в 2NF
-- ✅ В 2NF
CREATE TABLE Employees (
employee_id INT PRIMARY KEY,
employee_name VARCHAR(100),
department_id INT,
salary DECIMAL(10, 2),
FOREIGN KEY (department_id) REFERENCES Departments(department_id)
);
CREATE TABLE Departments (
department_id INT PRIMARY KEY,
department_name VARCHAR(100)
);
CREATE TABLE EmployeeProjects (
employee_id INT,
project_id INT,
project_hours INT,
PRIMARY KEY (employee_id, project_id),
FOREIGN KEY (employee_id) REFERENCES Employees(employee_id),
FOREIGN KEY (project_id) REFERENCES Projects(project_id)
);
CREATE TABLE Projects (
project_id INT PRIMARY KEY,
project_name VARCHAR(100)
);
Симптомы нарушения 2NF
Признаки того, что таблица НЕ в 2NF:
-
Дублирование данных
-- Одна информация о товаре повторяется в разных строках order_id | product_id | product_name | product_price | quantity 1 | 101 | "Ноутбук" | 1000.00 | 1 1 | 102 | "Мышка" | 20.00 | 2 2 | 101 | "Ноутбук" | 1000.00 | 1 ← Дублирование! -
Аномалия обновления (Update Anomaly)
- Если обновить price для product_id=101 в одной строке, нужно обновить во всех
-
Аномалия удаления (Deletion Anomaly)
- Если удалить последний заказ товара, потеряем информацию о товаре
-
Аномалия вставки (Insertion Anomaly)
- Нельзя добавить новый товар, если он не связан с заказом
Таблица сравнения: 1NF vs 2NF
| Критерий | 1NF | 2NF |
|---|---|---|
| Атомарные значения | ✅ Да | ✅ Да |
| Первичный ключ | ✅ Есть | ✅ Есть |
| Полная зависимость | ❌ Нет | ✅ Да |
| Частичные зависимости | ❌ Могут быть | ✅ Нет |
| Дублирование | ❌ Возможно | ✅ Минимально |
Практический алгоритм проверки 2NF
1. Проверь, есть ли в таблице составной первичный ключ (несколько полей)
Если НЕТ → таблица может быть в 2NF
Если ДА → перейди к шагу 2
2. Для каждого неключевого атрибута проверь:
Зависит ли он от ВСЕХ полей первичного ключа?
Если ДА → нормально
Если НЕТ (зависит только от части) → НАРУШЕНИЕ 2NF!
3. Если нашёл нарушение → разделить таблицу
Когда применяется 2NF?
✅ Используй 2NF для:
- Любой реляционной БД (SQL Server, PostgreSQL, MySQL)
- Систем с составными первичными ключами
- Когда много таблиц со связями many-to-many
⚠️ Возможные исключения:
- NoSQL системы (не реляционные)
- Денормализация для производительности (OLAP системы)
- Специальные случаи в data warehouse
Взаимосвязь: 1NF → 2NF → 3NF
1NF: Атомарные значения
↓
2NF: Нет частичных зависимостей (+ требования 1NF)
↓
3NF: Нет транзитивных зависимостей (+ требования 2NF)
Best Practices
✅ Правильно:
- Выделяй в отдельные таблицы данные, зависящие от части ключа
- Используй foreign keys для связи таблиц
- Думай о составном ключе: от каких частей ключа зависит каждый атрибут?
- Проверяй на дублирование данных
❌ Неправильно:
- Не помещай в таблицу данные, зависящие только от части ключа
- Не дублируй информацию в разных строках
- Не игнорируй признаки нарушения (дублирование, аномалии)
Вывод
Вторая нормальная форма (2NF) требует, чтобы:
- Таблица была в 1NF (атомарные значения)
- Все неключевые атрибуты полностью зависели от первичного ключа (а не от его части)
- Нет частичных зависимостей
Практический результат:
- Нет дублирования данных
- Нет аномалий обновления, удаления и вставки
- Данные легче обновлять и поддерживать
- Целостность БД гарантирована
Простое правило: Если у тебя составной ключ (например, student_id + course_id), убедись, что каждый неключевой атрибут зависит от ОБОИХ полей ключа, а не только от одного.