← Назад к вопросам
Что такое первая нормальная форма базы данных?
2.0 Middle🔥 141 комментариев
#Базы данных (SQL)
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Первая нормальная форма (1NF) — Атомарность данных
Первая нормальная форма (1NF) — это основной уровень нормализации БД, который требует, чтобы все значения в таблице были атомарными (неделимыми).
Основное правило 1NF
- Каждая ячейка таблицы должна содержать одно значение, а не список или составной тип
- Не должно быть повторяющихся групп данных
- Каждый столбец должен содержать только одно значение одного типа данных
- Должен быть первичный ключ для уникальной идентификации строк
Пример: Нарушение 1NF
-- ❌ ПЛОХО: нарушает 1NF
CREATE TABLE students (
id INT PRIMARY KEY,
name VARCHAR(100),
phone VARCHAR(100), -- Может содержать несколько номеров: '123-456, 789-101'
skills VARCHAR(255) -- Может содержать список: 'Python, Java, JavaScript'
);
-- Данные
INSERT INTO students VALUES
(1, 'Алиса', '123-456, 789-101', 'Python, Java, JavaScript'),
(2, 'Боб', '555-1234', 'C++, Rust');
Проблемы:
- Сложно искать студентов с телефоном 123-456
- Сложно найти всех, кто знает Python
- Сложно добавить один навык студенту
- Сложно удалить один навык
Решение: Соответствие 1NF
-- ✅ ХОРОШО: соответствует 1NF
CREATE TABLE students (
id INT PRIMARY KEY,
name VARCHAR(100)
);
CREATE TABLE phones (
id INT PRIMARY KEY,
student_id INT,
phone VARCHAR(15),
FOREIGN KEY (student_id) REFERENCES students(id)
);
CREATE TABLE skills (
id INT PRIMARY KEY,
student_id INT,
skill VARCHAR(50),
FOREIGN KEY (student_id) REFERENCES students(id)
);
-- Данные
INSERT INTO students VALUES (1, 'Алиса'), (2, 'Боб');
INSERT INTO phones VALUES (1, 1, '123-456'), (2, 1, '789-101'), (3, 2, '555-1234');
INSERT INTO skills VALUES (1, 1, 'Python'), (2, 1, 'Java'), (3, 1, 'JavaScript'), (4, 2, 'C++'), (5, 2, 'Rust');
Пример с использованием Python + SQLAlchemy
from sqlalchemy import create_engine, Column, Integer, String, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
Base = declarative_base()
# ❌ Нарушение 1NF (использовать НЕ нужно)
class StudentBad(Base):
__tablename__ = 'students_bad'
id = Column(Integer, primary_key=True)
name = Column(String)
phone = Column(String) # Может быть '123, 456, 789'
skills = Column(String) # Может быть 'Python, Java, JavaScript'
# ✅ Соответствие 1NF
class Student(Base):
__tablename__ = 'students'
id = Column(Integer, primary_key=True)
name = Column(String, nullable=False)
phones = relationship('Phone', back_populates='student')
skills_rel = relationship('StudentSkill', back_populates='student')
class Phone(Base):
__tablename__ = 'phones'
id = Column(Integer, primary_key=True)
student_id = Column(Integer, ForeignKey('students.id'))
phone = Column(String, nullable=False)
student = relationship('Student', back_populates='phones')
class StudentSkill(Base):
__tablename__ = 'student_skills'
id = Column(Integer, primary_key=True)
student_id = Column(Integer, ForeignKey('students.id'))
skill = Column(String, nullable=False)
student = relationship('Student', back_populates='skills_rel')
Практические примеры нарушений 1NF
Пример 1: Адреса
-- ❌ ПЛОХО
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(100),
address VARCHAR(255) -- '123 Main St, New York, NY 10001, USA'
);
-- ✅ ХОРОШО
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(100)
);
CREATE TABLE addresses (
id INT PRIMARY KEY,
user_id INT,
street VARCHAR(100),
city VARCHAR(50),
state VARCHAR(50),
zip VARCHAR(10),
country VARCHAR(50),
FOREIGN KEY (user_id) REFERENCES users(id)
);
Пример 2: Теги
-- ❌ ПЛОХО
CREATE TABLE posts (
id INT PRIMARY KEY,
title VARCHAR(255),
tags VARCHAR(255) -- 'python, django, web-development'
);
-- ✅ ХОРОШО
CREATE TABLE posts (
id INT PRIMARY KEY,
title VARCHAR(255)
);
CREATE TABLE tags (
id INT PRIMARY KEY,
name VARCHAR(100) UNIQUE
);
CREATE TABLE post_tags (
post_id INT,
tag_id INT,
PRIMARY KEY (post_id, tag_id),
FOREIGN KEY (post_id) REFERENCES posts(id),
FOREIGN KEY (tag_id) REFERENCES tags(id)
);
Преимущества 1NF
- Легче искать данные:
SELECT * FROM skills WHERE skill = 'Python' - Легче обновлять: Изменить один навык без влияния на другие
- Легче удалять: Удалить один телефон без удаления студента
- Нет дублирования: Студента нужно вводить один раз
- Целостность данных: FOREIGN KEY обеспечивает консистентность
На интервью
Ответи так:
"Первая нормальная форма требует, чтобы каждая ячейка таблицы содержала одно атомарное значение, а не список или составной тип. Например, вместо хранения 'Python, Java, JavaScript' в одной колонке, нужно создать отдельную таблицу skills и связать её через внешний ключ. Это избегает дублирования, упрощает запросы и гарантирует целостность данных."