← Назад к вопросам

Что такое ForeignKey?

1.2 Junior🔥 193 комментариев
#Базы данных и SQL

Комментарии (3)

🐱
claude-haiku-4.5PrepBro AI30 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Что такое ForeignKey?

ForeignKey (внешний ключ) — это ограничение целостности в базе данных, которое устанавливает связь между двумя таблицами. Это одно из ключевых понятий в реляционных БД.

Определение

ForeignKey — это столбец (или набор столбцов) в одной таблице, который ссылается на первичный ключ (Primary Key) в другой таблице. Это обеспечивает ссылочную целостность данных.

Базовая концепция

-- Таблица с Primary Key (родительская)
CREATE TABLE users (
    id INT PRIMARY KEY,
    name VARCHAR(100) NOT NULL
);

-- Таблица с Foreign Key (дочерняя)
CREATE TABLE posts (
    id INT PRIMARY KEY,
    user_id INT NOT NULL,
    title VARCHAR(255),
    FOREIGN KEY (user_id) REFERENCES users(id)
);

Здесь user_id в таблице posts — это внешний ключ, который ссылается на id в таблице users.

Как это работает

1. Ссылочная целостность

BD гарантирует, что:

-- Можно добавить
INSERT INTO posts (id, user_id, title) VALUES (1, 1, 'Post 1');
-- (если user_id = 1 существует в таблице users)

-- НЕЛЬЗЯ добавить
INSERT INTO posts (id, user_id, title) VALUES (2, 999, 'Post 2');
-- Ошибка! user_id = 999 не существует в users

2. Синтаксис Foreign Key

-- Способ 1: Inline определение
CREATE TABLE posts (
    id INT PRIMARY KEY,
    user_id INT REFERENCES users(id),
    title VARCHAR(255)
);

-- Способ 2: Отдельное ограничение
CREATE TABLE posts (
    id INT PRIMARY KEY,
    user_id INT,
    title VARCHAR(255),
    CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES users(id)
);

-- Способ 3: На существующей таблице
ALTER TABLE posts
ADD CONSTRAINT fk_user
FOREIGN KEY (user_id) REFERENCES users(id);

Каскадные действия (Cascade)

ForeignKey может автоматически обновлять или удалять записи при изменении родительской таблицы:

1. CASCADE (Каскадное удаление)

CREATE TABLE posts (
    id INT PRIMARY KEY,
    user_id INT NOT NULL,
    title VARCHAR(255),
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);

-- Если удалить пользователя, его посты тоже удалятся
DELETE FROM users WHERE id = 1;  -- Все posts с user_id=1 удалятся

2. SET NULL (Обнулить)

CREATE TABLE posts (
    id INT PRIMARY KEY,
    user_id INT,
    title VARCHAR(255),
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL
);

-- Если удалить пользователя, user_id в posts станет NULL
DELETE FROM users WHERE id = 1;  -- posts.user_id = NULL

3. SET DEFAULT

CREATE TABLE posts (
    id INT PRIMARY KEY,
    user_id INT DEFAULT 0,
    title VARCHAR(255),
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET DEFAULT
);

4. NO ACTION / RESTRICT

FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE RESTRICT;
-- Удаление будет запрещено, если есть зависимые записи

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

Пример 1: Блог

CREATE TABLE authors (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100) NOT NULL
);

CREATE TABLE articles (
    id INT PRIMARY KEY AUTO_INCREMENT,
    author_id INT NOT NULL,
    title VARCHAR(255),
    content TEXT,
    FOREIGN KEY (author_id) REFERENCES authors(id) ON DELETE CASCADE
);

CREATE TABLE comments (
    id INT PRIMARY KEY AUTO_INCREMENT,
    article_id INT NOT NULL,
    author_id INT NOT NULL,
    text TEXT,
    FOREIGN KEY (article_id) REFERENCES articles(id) ON DELETE CASCADE,
    FOREIGN KEY (author_id) REFERENCES authors(id) ON DELETE CASCADE
);

Пример 2: E-commerce

CREATE TABLE customers (
    id INT PRIMARY KEY,
    name VARCHAR(100)
);

CREATE TABLE orders (
    id INT PRIMARY KEY,
    customer_id INT NOT NULL,
    order_date TIMESTAMP,
    FOREIGN KEY (customer_id) REFERENCES customers(id)
);

CREATE TABLE order_items (
    id INT PRIMARY KEY,
    order_id INT NOT NULL,
    product_id INT NOT NULL,
    quantity INT,
    FOREIGN KEY (order_id) REFERENCES orders(id) ON DELETE CASCADE
);

Использование в C++ (C++17 пример)

#include <sqlite3.h>
#include <string>

class Database {
pubate:
    sqlite3* db;
    
    void createTables() {
        const char* sql = R"(
            CREATE TABLE IF NOT EXISTS users (
                id INTEGER PRIMARY KEY,
                name TEXT NOT NULL
            );
            
            CREATE TABLE IF NOT EXISTS posts (
                id INTEGER PRIMARY KEY,
                user_id INTEGER NOT NULL,
                title TEXT,
                FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
            );
        )";
        
        char* errMsg = nullptr;
        int rc = sqlite3_exec(db, sql, nullptr, nullptr, &errMsg);
        if (rc != SQLITE_OK) {
            std::cerr << "SQL error: " << errMsg << std::endl;
            sqlite3_free(errMsg);
        }
    }
    
    void insertPost(int userId, const std::string& title) {
        const char* sql = "INSERT INTO posts (user_id, title) VALUES (?, ?)";
        sqlite3_stmt* stmt;
        sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr);
        sqlite3_bind_int(stmt, 1, userId);
        sqlite3_bind_text(stmt, 2, title.c_str(), -1, SQLITE_STATIC);
        
        if (sqlite3_step(stmt) != SQLITE_DONE) {
            std::cerr << "Insert failed: " << sqlite3_errmsg(db) << std::endl;
            // Если user_id не существует, будет ошибка Foreign Key constraint
        }
        sqlite3_finalize(stmt);
    }
};

Преимущества ForeignKey

  1. Ссылочная целостность: БД гарантирует, что данные консистентны
  2. Защита от ошибок: Предотвращает создание orphaned records (сирот)
  3. Каскадные операции: Автоматическое удаление зависимых данных
  4. Документация: Явно показывает связи между таблицами

Недостатки

  1. Производительность: Проверка FK требует дополнительных запросов
  2. Сложность миграций: Нужно осторожно обновлять связанные таблицы
  3. Порядок операций: Нужно учитывать порядок удалений

Вывод

ForeignKey — это критически важный инструмент для обеспечения целостности данных в реляционных БД. Backend-разработчики должны понимать, как их использовать, чтобы избежать data corruption и написать надёжный код для работы с БД.

Что такое ForeignKey? | PrepBro