NodeJS Back-end Инженер

NodeJS Back-end Инженер

Роадмап навыков для прокачки

Что такое constraints и зачем они нужны в таблице?

DatabasesSQLConstraints

Основная идея

Constraints (ограничения) — это правила, которые применяются к данным в таблицах SQL для обеспечения целостности, точности и надёжности данных. Они автоматически контролируют, какие значения можно вставить в столбцы.

Ключевые аспекты

  • NOT NULL — запрещает пустые значения в столбце
  • UNIQUE — гарантирует уникальность всех значений в столбце
  • PRIMARY KEY — комбинация NOT NULL и UNIQUE, идентифицирует запись
  • FOREIGN KEY — связывает таблицы и обеспечивает ссылочную целостность
  • CHECK — проверяет значения по заданному условию
  • DEFAULT — устанавливает значение по умолчанию

Плюсы использования constraints

  • Автоматическая валидация данных на уровне БД
  • Защита от некорректных данных независимо от приложения
  • Поддержание целостности связей между таблицами
  • Уменьшение количества ошибок в данных

Минусы

  • Дополнительная нагрузка на БД при INSERT/UPDATE операциях
  • Необходимость продумывать constraints заранее
  • Сложность изменения constraints в production

Частые ошибки на собеседованиях

  • Путают PRIMARY KEY и UNIQUE (PRIMARY KEY = UNIQUE + NOT NULL)
  • Забывают, что FOREIGN KEY требует существования ссылаемого значения
  • Не знают разницу между CHECK и валидацией на уровне приложения

Введение и проблематика

При работе с базами данных критически важно обеспечить целостность данных — гарантию того, что данные корректны, согласованы и соответствуют бизнес-правилам. Без ограничений любое приложение могло бы записать в базу некорректные данные: пользователя без email, заказ с отрицательной ценой, или ссылку на несуществующую запись.

Constraints работают как «охранники» базы данных — они проверяют каждую операцию INSERT, UPDATE и DELETE, отклоняя те, что нарушают установленные правила.

Какую проблему решают constraints?

  1. Защита от человеческих ошибок — даже если разработчик забудет проверку в коде
  2. Единая точка валидации — правила хранятся в одном месте (БД), а не дублируются в каждом приложении
  3. Ссылочная целостность — невозможно создать «висячие» ссылки на удалённые записи

Базовая теория

Что такое constraint?

Constraint (ограничение) — это декларативное правило, определённое на уровне столбца или таблицы, которое автоматически проверяется СУБД при каждой операции изменения данных.

Типы constraints в SQL

ConstraintОписаниеУровень
NOT NULLЗапрещает NULL значенияСтолбец
UNIQUEВсе значения должны быть уникальныСтолбец/Таблица
PRIMARY KEYУникальный идентификатор записи (NOT NULL + UNIQUE)Столбец/Таблица
FOREIGN KEYСсылка на PRIMARY KEY другой таблицыСтолбец/Таблица
CHECKПроизвольное условие проверкиСтолбец/Таблица
DEFAULTЗначение по умолчаниюСтолбец

Практические примеры

NOT NULL — обязательные поля

sql
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    email VARCHAR(255) NOT NULL,  -- email обязателен
    nickname VARCHAR(50)          -- nickname опционален
);
 
-- ✅ Успешно
INSERT INTO users (email) VALUES ('user@example.com');
 
-- ❌ Ошибка: Column 'email' cannot be null
INSERT INTO users (nickname) VALUES ('john');

UNIQUE — уникальные значения

sql
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    email VARCHAR(255) UNIQUE NOT NULL,
    phone VARCHAR(20) UNIQUE
);
 
-- ✅ Успешно
INSERT INTO users (email, phone) VALUES ('a@test.com', '+1234567890');
 
-- ❌ Ошибка: Duplicate entry 'a@test.com' for key 'email'
INSERT INTO users (email, phone) VALUES ('a@test.com', '+0987654321');
⚠️

UNIQUE допускает несколько NULL значений в большинстве СУБД (PostgreSQL, MySQL). Это логично: NULL означает «неизвестно», а два «неизвестных» значения не считаются равными.

PRIMARY KEY — идентификатор записи

sql
CREATE TABLE products (
    id SERIAL PRIMARY KEY,  -- автоинкремент + NOT NULL + UNIQUE
    sku VARCHAR(50) NOT NULL,
    name VARCHAR(255) NOT NULL
);
 
-- Составной PRIMARY KEY
CREATE TABLE order_items (
    order_id INT,
    product_id INT,
    quantity INT NOT NULL,
    PRIMARY KEY (order_id, product_id)  -- уникальная комбинация
);

FOREIGN KEY — связь между таблицами

sql
CREATE TABLE orders (
    id SERIAL PRIMARY KEY,
    user_id INT NOT NULL,
    total DECIMAL(10, 2),
    FOREIGN KEY (user_id) REFERENCES users(id)
);
 
-- ✅ Успешно (если пользователь с id=1 существует)
INSERT INTO orders (user_id, total) VALUES (1, 99.99);
 
-- ❌ Ошибка: Cannot add or update a child row:
-- a foreign key constraint fails
INSERT INTO orders (user_id, total) VALUES (9999, 50.00);

CHECK — произвольные условия

sql
CREATE TABLE products (
    id SERIAL PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    price DECIMAL(10, 2) CHECK (price >= 0),
    quantity INT CHECK (quantity >= 0),
    status VARCHAR(20) CHECK (status IN ('active', 'inactive', 'archived'))
);
 
-- ✅ Успешно
INSERT INTO products (name, price, quantity, status)
VALUES ('Laptop', 999.99, 10, 'active');
 
-- ❌ Ошибка: Check constraint 'products_chk_1' is violated
INSERT INTO products (name, price, quantity, status)
VALUES ('Phone', -100, 5, 'active');

DEFAULT — значения по умолчанию

sql
CREATE TABLE articles (
    id SERIAL PRIMARY KEY,
    title VARCHAR(255) NOT NULL,
    status VARCHAR(20) DEFAULT 'draft',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    views INT DEFAULT 0
);
 
-- created_at, status и views заполнятся автоматически
INSERT INTO articles (title) VALUES ('My First Article');

Визуализация связей через FOREIGN KEY

erDiagram USERS ||--o{ ORDERS : "has" USERS { int id PK varchar email varchar name } ORDERS ||--|{ ORDER_ITEMS : "contains" ORDERS { int id PK int user_id FK decimal total } ORDER_ITEMS }|--|| PRODUCTS : "references" ORDER_ITEMS { int order_id PK,FK int product_id PK,FK int quantity } PRODUCTS { int id PK varchar name decimal price }

Пограничные кейсы

⚠️

Порядок создания таблиц: При использовании FOREIGN KEY сначала создаётся родительская таблица (на которую ссылаются), затем дочерняя (которая ссылается).

Каскадные операции

sql
CREATE TABLE orders (
    id SERIAL PRIMARY KEY,
    user_id INT NOT NULL,
    FOREIGN KEY (user_id) REFERENCES users(id)
        ON DELETE CASCADE      -- удаление пользователя удалит все его заказы
        ON UPDATE CASCADE      -- изменение id пользователя обновит ссылки
);

Варианты действий при удалении/обновлении:

  • CASCADE — автоматически удалить/обновить связанные записи
  • SET NULL — установить NULL в связанных записях
  • SET DEFAULT — установить значение по умолчанию
  • RESTRICT / NO ACTION — запретить операцию (по умолчанию)

Сравнение: валидация в БД vs в приложении

Плюсы:
  • Гарантированная защита независимо от источника данных
  • Единая точка правды
  • Работает даже при прямом доступе к БД
Минусы:
  • Нагрузка на БД
  • Сообщения об ошибках менее user-friendly
  • Сложнее изменять в production

Best practice: Используйте оба подхода. Constraints в БД — как последний рубеж защиты, валидация в приложении — для UX и бизнес-логики.


Плюсы и минусы constraints

АспектПлюсыМинусы
Целостность✅ Гарантированная защита данных
Производительность❌ Дополнительные проверки при записи
Разработка✅ Меньше багов с данными❌ Нужно продумывать заранее
Миграции❌ Сложно изменять существующие constraints
Масштабирование✅ Индексы на UNIQUE/PK ускоряют чтение❌ FK могут замедлять запись

Вопросы интервьюера

Q: Чем PRIMARY KEY отличается от UNIQUE?

PRIMARY KEY = UNIQUE + NOT NULL. В таблице может быть только один PRIMARY KEY, но несколько UNIQUE constraints.

Q: Можно ли добавить FOREIGN KEY на столбец с существующими некорректными данными?

Нет, СУБД выдаст ошибку. Сначала нужно исправить данные или удалить «сиротские» записи.

Q: Какой constraint использовать для проверки email?

CHECK с регулярным выражением (если СУБД поддерживает) или валидация на уровне приложения. CHECK лучше для простых проверок.

Q: Влияют ли constraints на производительность?

Да. UNIQUE и FOREIGN KEY создают индексы, что ускоряет SELECT, но замедляет INSERT/UPDATE. CHECK выполняет дополнительные проверки.


Источники