Назови три нормальные формы в SQL

Ответ

1. Первая нормальная форма (1NF) Таблица находится в 1NF, если:

  • Все значения атрибутов атомарны (неделимы). Нет составных значений, массивов или списков в одной ячейке.
  • Нет повторяющихся групп столбцов.
  • Определён первичный ключ (явно или неявно).

Пример нарушения и исправления:

-- НАРУШЕНИЕ 1NF: неатомарное значение, список в одной ячейке
CREATE TABLE Orders (
    order_id INT PRIMARY KEY,
    customer_name VARCHAR(100),
    items VARCHAR(500) -- Например: 'Laptop, Mouse, Keyboard'
);

-- СООТВЕТСТВИЕ 1NF: каждая сущность в отдельной строке
CREATE TABLE OrderItems (
    order_id INT,
    item_name VARCHAR(100),
    quantity INT,
    PRIMARY KEY (order_id, item_name),
    FOREIGN KEY (order_id) REFERENCES Orders(order_id)
);
-- Данные: (1, 'Laptop', 1), (1, 'Mouse', 1), (1, 'Keyboard', 1)

2. Вторая нормальная форма (2NF) Таблица находится в 2NF, если:

  • Она уже в 1NF.
  • Все неключевые атрибуты полностью функционально зависят от всего составного первичного ключа (нет частичных зависимостей).

Пример нарушения и исправления:

-- НАРУШЕНИЕ 2NF: цена зависит только от product_id, а не от пары (order_id, product_id)
CREATE TABLE OrderDetails (
    order_id INT,
    product_id INT,
    product_name VARCHAR(100), -- Частичная зависимость: зависит только от product_id
    price DECIMAL(10,2),      -- Частичная зависимость: зависит только от product_id
    quantity INT,
    PRIMARY KEY (order_id, product_id)
);

-- СООТВЕТСТВИЕ 2NF: выносим частичные зависимости в отдельную таблицу
CREATE TABLE Products (
    product_id INT PRIMARY KEY,
    product_name VARCHAR(100),
    price DECIMAL(10,2)
);

CREATE TABLE OrderDetails (
    order_id INT,
    product_id INT,
    quantity INT,
    PRIMARY KEY (order_id, product_id),
    FOREIGN KEY (product_id) REFERENCES Products(product_id)
);

3. Третья нормальная форма (3NF) Таблица находится в 3NF, если:

  • Она уже в 2NF.
  • Нет транзитивных зависимостей: неключевые атрибуты не зависят от других неключевых атрибутов, а только от первичного ключа.

Пример нарушения и исправления:

-- НАРУШЕНИЕ 3NF: manager зависит от department, а не напрямую от emp_id (транзитивная зависимость)
CREATE TABLE Employees (
    emp_id INT PRIMARY KEY,
    emp_name VARCHAR(100),
    department VARCHAR(50),
    department_manager VARCHAR(100) -- Зависит от department, а не от emp_id
);

-- СООТВЕТСТВИЕ 3NF: выносим транзитивную зависимость
CREATE TABLE Departments (
    department_name VARCHAR(50) PRIMARY KEY,
    manager VARCHAR(100)
);

CREATE TABLE Employees (
    emp_id INT PRIMARY KEY,
    emp_name VARCHAR(100),
    department VARCHAR(50),
    FOREIGN KEY (department) REFERENCES Departments(department_name)
);

Практический итог: Нормализация уменьшает избыточность данных и аномалии при вставке, обновлении и удалении, но может увеличивать количество JOIN-запросов. Часто идут на компромисс, денормализируя таблицы для производительности на чтение в аналитических системах (OLAP).

Ответ 18+ 🔞

А, нормальные формы, классика жанра! Ну что, разбираем эту матчасть, чтобы не было потом пиздеца в базе данных. Слушай сюда, но не засыпай.

1. Первая нормальная форма (1NF) Это как элементарные правила гигиены, блядь. Таблица в порядке, если:

  • В каждой ячейке лежит один простой кусок данных, а не какой-нибудь салат из значений. Никаких списков через запятую — это пиздопроебибна.
  • Нет столбцов-близнецов, которые одно и то же означают.
  • Есть чёткий главный ключ, который всё идентифицирует. Без этого — пизда рулю.

Смотри, как бывает:

-- КАК НЕ НАДО: запихнул всё в одну кучу, как маньяк
CREATE TABLE Orders (
    order_id INT PRIMARY KEY,
    customer_name VARCHAR(100),
    items VARCHAR(500) -- Типа 'Ноутбук, Мышь, Клавиатура' — овердохуища говна в одной ячейке
);
-- КАК НАДО: разложил по полочкам, как человек
CREATE TABLE OrderItems (
    order_id INT,
    item_name VARCHAR(100),
    quantity INT,
    PRIMARY KEY (order_id, item_name),
    FOREIGN KEY (order_id) REFERENCES Orders(order_id)
);
-- Данные теперь нормальные: (1, 'Ноутбук', 1), (1, 'Мышь', 1), (1, 'Клавиатура', 1)

Видишь разницу? В первом случае — хитрая жопа, которая взорвётся при первом же запросе. Во втором — красота.

2. Вторая нормальная форма (2NF) Тут уже посерьёзнее. Чтобы было всё чинно:

  • Таблица уже должна быть в 1NF (логично, ёпта).
  • Все неключевые поля должны жёстко зависеть от ВСЕГО составного первичного ключа. Если зависят только от части — это хуй с горы, а не зависимость.

Лови пример:

-- НАРУШЕНИЕ: цена и имя товара прилипли только к product_id, а order_id тут как пятое колесо
CREATE TABLE OrderDetails (
    order_id INT,
    product_id INT,
    product_name VARCHAR(100), -- Зависит только от product_id! Подозрение ебать чувствую!
    price DECIMAL(10,2),      -- И это тоже! Частичная зависимость, мать его!
    quantity INT,
    PRIMARY KEY (order_id, product_id)
);
-- ИСПРАВЛЕНИЕ: раскидал по своим углам
CREATE TABLE Products (
    product_id INT PRIMARY KEY,
    product_name VARCHAR(100),
    price DECIMAL(10,2)
);

CREATE TABLE OrderDetails (
    order_id INT,
    product_id INT,
    quantity INT,
    PRIMARY KEY (order_id, product_id),
    FOREIGN KEY (product_id) REFERENCES Products(product_id)
);

Вынес информацию о товаре отдельно. Теперь если цена поменяется, её надо править в одном месте, а не впиздюривать во все заказы разом. Удобно, да?

3. Третья нормальная форма (3NF) А это уже высший пилотаж. Условия:

  • 2NF пройдена (само собой).
  • Никаких транзитивных зависимостей! То есть неключевые поля не должны зависеть от других неключевых полей. Только от ключа, блядь! Иначе получается цепочка, доверия ебать ноль.

Смотри, как ловко нарушают:

-- НАРУШЕНИЕ: менеджер привязан к отделу, а не к сотруднику. Транзитивная зависимость!
CREATE TABLE Employees (
    emp_id INT PRIMARY KEY,
    emp_name VARCHAR(100),
    department VARCHAR(50),
    department_manager VARCHAR(100) -- Вот же ж, мудя! Зависит от department, а не от emp_id!
);
-- ИСПРАВЛЕНИЕ: развёл по разным квартирам
CREATE TABLE Departments (
    department_name VARCHAR(50) PRIMARY KEY,
    manager VARCHAR(100)
);

CREATE TABLE Employees (
    emp_id INT PRIMARY KEY,
    emp_name VARCHAR(100),
    department VARCHAR(50),
    FOREIGN KEY (department) REFERENCES Departments(department_name)
);

Теперь если начальник отдела сменится, мы меняем одну запись в Departments, а не бегаем и впендюриваем новую фамилию каждому сотруднику. Волнение ебать прошло.

Итог, чувак: Нормализация — это чтобы данные не дублировались и не было аномалий при обновлении. Но за всё надо платить: чем больше таблиц, тем больше JOIN-ов, а это может тормозить. Поэтому для тяжёлых отчётов (OLAP) иногда специально денормализуют — жертвуют аккуратностью ради скорости. Но чтобы нарушать правила, их надо сначала знать, верно? Иначе будет тебе хиросима и нигерсраки в продакшене.