NodeJS Back-end Инженер

NodeJS Back-end Инженер

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

Что такое связь между таблицами (relationship)?

DatabasesSQLRelationship

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

Relationship (связь) между таблицами — это логическая связь, которая соединяет данные из разных таблиц на основе общих значений. В SQL связи реализуются через FOREIGN KEY, который ссылается на PRIMARY KEY другой таблицы.

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

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

Зачем нужны связи?

  • Устранение дублирования данных
  • Поддержание консистентности информации
  • Логическая организация данных
  • Возможность делать JOIN-запросы

Плюсы

  • Экономия места (данные не дублируются)
  • Изменение данных в одном месте обновляет всю систему
  • Структурированность и понятность схемы

Минусы

  • Требуется понимание нормализации
  • JOIN-запросы сложнее простых SELECT
  • Производительность может снижаться при многих JOIN

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

  • Путают связь (relationship) с JOIN-операцией
  • Не понимают разницу между логической связью и физическим FOREIGN KEY
  • Забывают про каскадные операции при удалении связанных записей

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

Представьте интернет-магазин, где нужно хранить информацию о пользователях и их заказах. Можно записать всё в одну таблицу:

sql
-- ❌ Плохой подход: всё в одной таблице
| order_id | user_name | user_email      | product  | price |
|----------|-----------|-----------------|----------|-------|
| 1        | John      | john@mail.com   | Laptop   | 999   |
| 2        | John      | john@mail.com   | Mouse    | 25    |
| 3        | John      | john@mail.com   | Keyboard | 75    |

Проблемы очевидны:

  • Дублирование: имя и email Джона повторяются 3 раза
  • Аномалии обновления: изменение email требует обновления всех строк
  • Аномалии удаления: удаление последнего заказа удалит и данные пользователя

Связи между таблицами (relationships) решают эти проблемы, разделяя данные по логическим сущностям и соединяя их через ключи.


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

Что такое relationship?

Relationship (связь) — это логическое соединение между двумя таблицами, основанное на общих данных. Одна таблица содержит PRIMARY KEY, другая — FOREIGN KEY, который ссылается на этот PRIMARY KEY.

Терминология

ТерминОписание
Родительская таблицаТаблица с PRIMARY KEY (на которую ссылаются)
Дочерняя таблицаТаблица с FOREIGN KEY (которая ссылается)
Ссылочная целостностьГарантия, что FOREIGN KEY указывает на существующую запись
КардинальностьТип связи: один-к-одному, один-ко-многим, многие-ко-многим

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

Разделение данных по таблицам

sql
-- ✅ Правильный подход: две связанные таблицы
 
-- Родительская таблица
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    email VARCHAR(255) UNIQUE NOT NULL
);
 
-- Дочерняя таблица со связью
CREATE TABLE orders (
    id SERIAL PRIMARY KEY,
    user_id INT NOT NULL,
    product VARCHAR(255) NOT NULL,
    price DECIMAL(10, 2) NOT NULL,
    FOREIGN KEY (user_id) REFERENCES users(id)
);

Теперь данные организованы правильно:

sql
-- Таблица users
| id | name | email         |
|----|------|---------------|
| 1  | John | john@mail.com |
 
-- Таблица orders
| id | user_id | product  | price |
|----|---------|----------|-------|
| 1  | 1       | Laptop   | 999   |
| 2  | 1       | Mouse    | 25    |
| 3  | 1       | Keyboard | 75    |

Получение связанных данных через JOIN

sql
-- Получить все заказы с информацией о пользователе
SELECT
    u.name,
    u.email,
    o.product,
    o.price
FROM orders o
JOIN users u ON o.user_id = u.id;

Результат:

text
| name | email         | product  | price |
|------|---------------|----------|-------|
| John | john@mail.com | Laptop   | 999   |
| John | john@mail.com | Mouse    | 25    |
| John | john@mail.com | Keyboard | 75    |

Визуализация связи

erDiagram USERS ||--o{ ORDERS : "has many" USERS { int id PK varchar name varchar email } ORDERS { int id PK int user_id FK varchar product decimal price }

Нотация:

  • || — один (обязательный)
  • o{ — много (опционально)
  • PK — Primary Key
  • FK — Foreign Key

Как работает FOREIGN KEY

FOREIGN KEY обеспечивает ссылочную целостность — невозможно создать заказ для несуществующего пользователя.

sql
-- ✅ Успешно: пользователь с id=1 существует
INSERT INTO orders (user_id, product, price) VALUES (1, 'Phone', 599);
 
-- ❌ Ошибка: пользователь с id=999 не существует
INSERT INTO orders (user_id, product, price) VALUES (999, 'Tablet', 399);
-- Error: a foreign key constraint fails

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

Что делать при удалении пользователя с заказами?

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

Варианты поведения:

ДействиеОписание
CASCADEАвтоматически удалить/обновить связанные записи
SET NULLУстановить NULL в дочерних записях
SET DEFAULTУстановить значение по умолчанию
RESTRICTЗапретить операцию, если есть связанные записи
NO ACTIONТо же, что RESTRICT (по умолчанию)

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

⚠️

Порядок операций важен! При вставке: сначала родительская запись, потом дочерняя. При удалении: сначала дочерние, потом родительская (или используйте CASCADE).

Правильный порядок вставки

sql
-- 1. Сначала создаём пользователя
INSERT INTO users (name, email) VALUES ('Alice', 'alice@mail.com');
-- Получаем id = 2
 
-- 2. Потом создаём заказ
INSERT INTO orders (user_id, product, price) VALUES (2, 'Monitor', 299);

Правильный порядок удаления (без CASCADE)

sql
-- 1. Сначала удаляем заказы пользователя
DELETE FROM orders WHERE user_id = 2;
 
-- 2. Потом удаляем пользователя
DELETE FROM users WHERE id = 2;

Связь vs JOIN

Relationship — это структурная связь между таблицами:

  • Определяется при создании таблицы
  • Реализуется через FOREIGN KEY
  • Обеспечивает целостность данных
  • Существует независимо от запросов
sql
-- Определение связи
FOREIGN KEY (user_id) REFERENCES users(id)

Можно делать JOIN без FOREIGN KEY, но тогда база данных не защитит от «сиротских» записей.


Преимущества связей между таблицами

АспектБез связейСо связями
Дублирование❌ Данные повторяются✅ Каждый факт хранится один раз
Обновление❌ Нужно менять много строк✅ Одно изменение в одном месте
Целостность❌ Возможны inconsistent данные✅ FOREIGN KEY гарантирует связь
Размер БД❌ Больше места на диске✅ Меньше места
Запросы✅ Простой SELECT❌ Нужен JOIN

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

Q: Чем relationship отличается от JOIN?

Relationship — это структурная связь через FOREIGN KEY. JOIN — операция в SQL-запросе для объединения данных. Можно делать JOIN без relationship, но тогда нет гарантии целостности.

Q: Можно ли сделать связь между таблицами без FOREIGN KEY?

Технически да, используя обычный столбец и JOIN по значениям. Но без FOREIGN KEY база не защитит от «сиротских» записей.

Q: Что такое ссылочная целостность?

Гарантия того, что значение FOREIGN KEY всегда указывает на существующую запись в родительской таблице.

Q: Как удалить запись, на которую есть ссылки?

Варианты: сначала удалить дочерние записи, использовать ON DELETE CASCADE, или ON DELETE SET NULL.


Источники