Нормальные формы
1НФ, 2НФ, 3НФ
Предисловие: на большинстве собеседований спрашивают именно первые три нормальные формы. 4НФ, 5НФ и 6НФ полезны для расширения кругозора, но в практике DE/DA обычно не нужны.
Нормальные формы — это правила, как раскладывать данные по таблицам, чтобы:
- не было лишних дубликатов,
- было удобно вставлять, обновлять и удалять данные,
- изменения в одном месте не ломали всё остальное.
Если хранить всё в одной таблице, начинаются проблемы:
- одинаковые значения повторяются десятки раз;
- при обновлении данных нужно менять их сразу в нескольких местах;
- легко получить несогласованные или «сломанные» записи.
Ниже — кратко и по делу про 1НФ, 2НФ, 3НФ.
1НФ (Первая нормальная форма)
Суть: в каждой ячейке одно значение, нет списков и «массивов» в столбцах.
Что запрещено в 1НФ:
- несколько значений в одном поле;
- повторяющиеся группы столбцов.
Пример нарушения:
таблица клиентов с полем phones, где лежит +7... , +7... , +7...
Как исправить: вынести телефоны в отдельную таблицу и хранить по одному значению в строке.
Как выглядят таблицы:
Таблица клиентов (1НФ):
| customer_id | name |
|---|---|
| C001 | Иван Петров |
| C002 | Анна Смирнова |
Таблица телефонов (1НФ):
| customer_id | phone |
|---|---|
| C001 | +7 999 111-22-33 |
| C001 | +7 999 444-55-66 |
| C002 | +7 999 777-88-99 |
2НФ (Вторая нормальная форма)
Суть: таблица уже в 1НФ и все неключевые поля зависят от всего ключа целиком.
Когда ломается 2НФ: если ключ составной, а некоторые поля зависят только от его части.
Пример:
таблица order_item(order_id, product_id, product_name, price)
product_nameиpriceзависят только отproduct_id, а не отorder_id.
Как исправить:
вынести информацию о продукте в отдельную таблицу product(product_id, product_name, price).
Как выглядят таблицы:
Таблица позиций заказа (2НФ):
| order_id | product_id | qty |
|---|---|---|
| O1001 | P10 | 2 |
| O1001 | P20 | 1 |
| O1002 | P10 | 1 |
Таблица продуктов (2НФ):
| product_id | product_name | price |
|---|---|---|
| P10 | Мышь | 1200 |
| P20 | Клавиатура | 3500 |
3НФ (Третья нормальная форма)
Суть: таблица в 2НФ и неключевые поля не зависят друг от друга.
Когда ломается 3НФ: если одно неключевое поле определяется другим неключевым.
Пример:
таблица employee(employee_id, department_id, department_name)
department_nameзависит отdepartment_id, а не отemployee_id.
Как исправить:
вынести department_name в отдельную таблицу department(department_id, department_name).
Как выглядят таблицы:
Таблица сотрудников (3НФ):
| employee_id | department_id | name |
|---|---|---|
| E01 | D10 | Алексей Орлов |
| E02 | D20 | Ольга Миронова |
Таблица отделов (3НФ):
| department_id | department_name |
|---|---|
| D10 | Аналитика |
| D20 | Разработка |
Итог в одном абзаце
Нормальные формы — это логика разбиения таблиц, чтобы данные были чистыми, обновлялись без боли и не содержали лишних дубликатов. На практике чаще всего достаточно понимать и уметь объяснить 1НФ, 2НФ и 3НФ.
Проще про разницу 2НФ и 3НФ (на одном примере)
Представим таблицу «Заказы товаров» с составным ключом (order_id, product_id):
| order_id | product_id | product_name | price | customer_name |
|---|---|---|---|---|
| O1 | P1 | Мышь | 1200 | Иван |
| O1 | P2 | Клава | 3500 | Иван |
| O2 | P1 | Мышь | 1200 | Ольга |
2НФ — «каждое поле зависит от всего ключа»
product_name и price зависят только от product_id, а не от order_id → 2НФ нарушена.
Фикс 2НФ:
- Таблица
order_item(order_id, product_id, qty) - Таблица
product(product_id, product_name, price)
3НФ — «неключевые поля не зависят друг от друга»
Если отдельно хранить заказ:
| order_id | customer_id | customer_name |
|---|---|---|
| O1 | C1 | Иван |
| O2 | C2 | Ольга |
customer_name зависит от customer_id, а не от order_id → 3НФ нарушена.
Фикс 3НФ:
- Таблица
orders(order_id, customer_id) - Таблица
customer(customer_id, customer_name)