Какие типы связей между таблицами существуют в реляционных базах данных?

«Какие типы связей между таблицами существуют в реляционных базах данных?» — вопрос из категории Базы данных, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

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

1. Один к одному (One-to-One, 1:1)

Одна запись в таблице А связана не более чем с одной записью в таблице Б, и наоборот.

Зачем это нужно? Часто используется для разделения сущности на несколько таблиц по соображениям:

  • Безопасности: Конфиденциальные данные (паспорт) отдельно от основных (пользователь).
  • Производительности: Часто запрашиваемые поля — в одной таблице, редко используемые — в другой.
  • Наследования (Table per Hierarchy): В ORM, например, для реализации наследования.

Реализация в БД: Внешний ключ создается в любой из таблиц, но должен быть также UNIQUE, чтобы гарантировать "один к одному".

CREATE TABLE Users (
    UserId INT PRIMARY KEY,
    Username NVARCHAR(50) NOT NULL
);

CREATE TABLE UserProfiles (
    ProfileId INT PRIMARY KEY,
    UserId INT UNIQUE NOT NULL, -- И FK, и UNIQUE!
    Bio NVARCHAR(MAX),
    CONSTRAINT FK_Profile_User FOREIGN KEY (UserId) REFERENCES Users(UserId)
);

2. Один ко многим (One-to-Many, 1:N)

Самая распространенная связь. Одна запись в таблице А может быть связана со многими записями в таблице Б, но запись в Б связана только с одной записью в А.

Примеры: BlogPosts, CustomerOrders, CountryCities.

Реализация в БД: Внешний ключ создается в таблице со стороны "многих" (таблица Б).

CREATE TABLE Blogs (
    BlogId INT PRIMARY KEY,
    Name NVARCHAR(100) NOT NULL
);

CREATE TABLE Posts (
    PostId INT PRIMARY KEY,
    Title NVARCHAR(200) NOT NULL,
    BlogId INT NOT NULL, -- FK на стороне "многих"
    CONSTRAINT FK_Post_Blog FOREIGN KEY (BlogId) REFERENCES Blogs(BlogId)
);

3. Многие ко многим (Many-to-Many, N:N)

Одна запись в А может быть связана со многими записями в Б, и наоборот.

Примеры: StudentsCourses, ProductsOrders, BooksAuthors.

Реализация в БД: Требуется промежуточная таблица-связка (junction/join table). Эта таблица содержит как минимум два внешних ключа, ссылающихся на первичные ключи связываемых таблиц. Ее составной ключ (PK1+PK2) уникален и предотвращает дублирование связей.

CREATE TABLE Students (
    StudentId INT PRIMARY KEY,
    Name NVARCHAR(100) NOT NULL
);

CREATE TABLE Courses (
    CourseId INT PRIMARY KEY,
    Title NVARCHAR(100) NOT NULL
);

-- Таблица-связка
CREATE TABLE StudentCourses (
    StudentId INT NOT NULL,
    CourseId INT NOT NULL,
    EnrollmentDate DATE,
    PRIMARY KEY (StudentId, CourseId), -- Составной первичный ключ
    CONSTRAINT FK_StudentCourse_Student FOREIGN KEY (StudentId) REFERENCES Students(StudentId),
    CONSTRAINT FK_StudentCourse_Course FOREIGN KEY (CourseId) REFERENCES Courses(CourseId)
);

Важно в ORM (Entity Framework Core): Для связи "многие ко многим" EF Core 5+ позволяет напрямую конфигурировать коллекции без явного создания класса для таблицы-связки, но под капотом она все равно создается.