Помогают ли внешние ключи (foreign keys) удалять данные в связанных таблицах?

Ответ

Внешние ключи (FK) сами по себе не удаляют данные. Их основная задача — обеспечить целостность ссылочных данных (referential integrity). Они гарантируют, что в дочерней таблице (order_items) не может существовать запись, ссылающаяся на несуществующую запись в родительской таблице (orders).

Однако, при определении внешнего ключа можно задать правило каскадного действия (ON DELETE). Вот как это работает:

-- Родительская таблица
CREATE TABLE orders (
    id INT PRIMARY KEY AUTO_INCREMENT,
    customer_id INT NOT NULL,
    total DECIMAL(10,2)
);

-- Дочерняя таблица с внешним ключом и разными правилами ON DELETE
CREATE TABLE order_items (
    id INT PRIMARY KEY AUTO_INCREMENT,
    order_id INT NOT NULL,
    product_id INT NOT NULL,
    quantity INT,
    -- 1. CASCADE: автоматическое удаление дочерних записей
    CONSTRAINT fk_items_order_cascade 
        FOREIGN KEY (order_id) REFERENCES orders(id) 
        ON DELETE CASCADE,

    -- 2. SET NULL: установка NULL в поле внешнего ключа (поле должно быть NULLABLE)
    -- CONSTRAINT fk_items_order_setnull 
    --    FOREIGN KEY (order_id) REFERENCES orders(id) 
    --    ON DELETE SET NULL,

    -- 3. RESTRICT (или NO ACTION): запрет удаления родительской записи, если есть дочерние
    -- CONSTRAINT fk_items_order_restrict 
    --    FOREIGN KEY (order_id) REFERENCES orders(id) 
    --    ON DELETE RESTRICT
);

Практический пример с CASCADE:

-- Вставка данных
INSERT INTO orders (id, customer_id, total) VALUES (101, 1, 150.00);
INSERT INTO order_items (order_id, product_id, quantity) VALUES (101, 500, 2);
INSERT INTO order_items (order_id, product_id, quantity) VALUES (101, 501, 1);

-- Удаление заказа. Благодаря ON DELETE CASCADE, две связанные строки в order_items будут удалены автоматически.
DELETE FROM orders WHERE id = 101;
-- После этого запрос SELECT * FROM order_items WHERE order_id = 101 вернет пустой результат.

Ключевые моменты:

  • ON DELETE CASCADE — это именно то правило, которое «помогает удалять» связанные данные автоматически. Используйте его с осторожностью, так как это может привести к неожиданной потере данных.
  • ON DELETE RESTRICT (или NO ACTION) — это поведение по умолчанию во многих СУБД. Оно не помогает удалить, а наоборот, предотвращает удаление, если существуют зависимые записи, защищая от «висячих» ссылок.
  • ON DELETE SET NULL — не удаляет дочернюю запись, а обнуляет ссылку. Для этого столбец order_id должен быть объявлен как INT NULL.

Вывод: Внешние ключи — это механизм поддержания целостности. Правило ON DELETE CASCADE — это опция, которая автоматизирует удаление зависимых записей, но ее применение должно быть осознанным и соответствовать бизнес-логике (например, удаление заказа должно удалять его позиции, но удаление клиента, вероятно, не должно удалять все его исторические заказы).

Ответ 18+ 🔞

А, ну это же классика, ёпта! Смотри, с внешними ключами постоянно путаница возникает, будто они сами по себе что-то удаляют. Хуй с горы! Их главная работа — следить, чтобы в твоей базе не появилось сирот-записей, которые тыкаются пальцем в пустоту.

Представь таблицу заказов (orders) — это как папа. А таблица позиций в заказе (order_items) — это его дети. Внешний ключ в order_items на orders.id — это просто верёвка, которая не даёт ребёнку убежать и назваться сиротой. Сам по себе он ничего не удаляет, он просто стоит и смотрит, чтобы хуйни не было.

Но! Если ты очень хочешь, чтобы при исчезновении папы дети тоже шли лесом, то это нужно явно прописать — правило ON DELETE CASCADE. Вот тогда да, удалил заказ — и все его позиции накрылись медным тазом автоматически. Но это твой сознательный выбор, а не магия.

CREATE TABLE orders (
    id INT PRIMARY KEY AUTO_INCREMENT,
    customer_id INT NOT NULL,
    total DECIMAL(10,2)
);

CREATE TABLE order_items (
    id INT PRIMARY KEY AUTO_INCREMENT,
    order_id INT NOT NULL,
    product_id INT NOT NULL,
    quantity INT,
    -- Вот этот самый CASCADE и есть наш "помощник" в удалении
    CONSTRAINT fk_items_order_cascade
        FOREIGN KEY (order_id) REFERENCES orders(id)
        ON DELETE CASCADE -- Смотри-ка, мама, что я могу!
);

На практике это выглядит так:

-- Был заказ 101 с двумя позициями
INSERT INTO orders (id, customer_id, total) VALUES (101, 1, 150.00);
INSERT INTO order_items (order_id, product_id, quantity) VALUES (101, 500, 2);
INSERT INTO order_items (order_id, product_id, quantity) VALUES (101, 501, 1);

-- Бац! И заказ 101 удаляем.
DELETE FROM orders WHERE id = 101;
-- И теперь волнение ебать: если полезешь в order_items искать позиции по order_id = 101, нихуя не найдёшь. CASCADE их прибрал.

А есть и другие правила, ядрёна вошь:

  • ON DELETE RESTRICT (или NO ACTION) — это как раз поведение по умолчанию у многих. Это не помощник, а охранник. Он тебе скажет: «Чувак, какого хуя? У тебя же дети (позиции) есть! Сначала разберись с ними, а потом уже папу удаляй». Удаление родителя просто не пройдёт.
  • ON DELETE SET NULL — это типа мягкий вариант. Папу удалили, а дети остались, но теперь у них в графе «папа» стоит NULL. Сиротами при живых родителях, грустная история. Для этого само поле order_id должно позволять быть пустым (NULL).

Так что вывод, бля, простой: сам внешний ключ — это просто верёвка для целостности. А вот ON DELETE CASCADE — это уже топор, который ты можешь вручить системе со словами «на, помоги». Пользуйся им с головой, а то так и до хиросимы в базе недалеко. Удалишь клиента по ошибке, а CASCADE тебе за ним все его заказы похерит — и пиши пропало.