Ответ
Foreign Key (внешний ключ) — это ограничение (constraint) в реляционных базах данных, которое используется для установления и поддержки связи между данными в двух таблицах. Он гарантирует ссылочную целостность данных.
Ключевые цели и функции:
-
Обеспечение ссылочной целостности: Внешний ключ не позволяет создавать записи в дочерней таблице, которые ссылаются на несуществующие записи в родительской таблице. Это предотвращает появление "осиротевших" данных.
-
Определение связей: Явно определяет отношения между таблицами, такие как "один-ко-многим" (
one-to-many) или "один-к-одному" (one-to-one). -
Каскадные операции (Cascading Actions): Позволяют автоматически управлять связанными данными при изменении родительской записи. Основные действия:
ON DELETE CASCADE: При удалении родительской записи автоматически удаляются все связанные дочерние записи.ON UPDATE CASCADE: При изменении первичного ключа родительской записи он автоматически обновляется во всех дочерних записях.ON DELETE SET NULL: При удалении родительской записи значение внешнего ключа в дочерних записях устанавливается вNULL.RESTRICT/NO ACTION(поведение по умолчанию): Запрещает удаление или обновление родительской записи, если на нее есть ссылки.
Пример в SQL:
-- Родительская таблица
CREATE TABLE customers (
id INT PRIMARY KEY,
name VARCHAR(255)
);
-- Дочерняя таблица
CREATE TABLE orders (
id INT PRIMARY KEY,
order_number VARCHAR(50),
customer_id INT,
-- Устанавливаем внешний ключ
FOREIGN KEY (customer_id)
REFERENCES customers(id)
ON DELETE SET NULL -- Если клиент удален, заказ останется, но без привязки
);
Пример в Go при работе с ORM (GORM):
// GORM автоматически распознает эту связь и создаст
// ограничение внешнего ключа при миграции.
type Customer struct {
ID uint
Name string
// У клиента может быть много заказов
Orders []Order
}
type Order struct {
ID uint
OrderNumber string
// Поле для внешнего ключа
CustomerID uint
// Принадлежность к структуре Customer
Customer Customer `gorm:"foreignKey:CustomerID"`
} Ответ 18+ 🔞
А, вот это, блядь, тема! Foreign Key, он же внешний ключ, ёпта! Это ж такая штука в базах данных, которая не даёт тебе наделать хуйни и связать заказы с клиентом, которого в природе не существует. Представь, блядь, ты пишешь в таблицу orders: «заказ от клиента с ID 666», а в таблице customers такого клиента — хуй с горы! Вот внешний ключ как раз и орёт: «Э, сабака, сука! Ты куда лезешь? Такого клиента нет, иди нахуй!»
Зачем он вообще нужен, этот ваш ключ?
- Чтоб не было сирот-пидорасов в данных. Это называется «ссылочная целостность». Нельзя привязать запись к призраку. Либо клиент есть, либо иди в пизду со своим заказом.
- Чтоб всем было понятно, кто на ком стоит. Сразу видно — вот эта таблица (
orders) подчинена вот этой (customers). Один ко многим. Один клиент — овердохуища заказов. - Автоматическая уборка за тобой, лентяем (Cascading Actions). Это вообще магия, блядь. Настроил — и база сама всё сделает.
ON DELETE CASCADE: Удалил клиента — все его заказы автоматом в пизду полетели. Чистота, блядь!ON UPDATE CASCADE: Поменял клиенту ID — во всех его заказах ID тоже поменяется. Удобно, ёпта!ON DELETE SET NULL: Клиента удалили, а заказы остались, но теперь в полеcustomer_idкрасуетсяNULL. Типа «заказ есть, а кто заказывал — хуй знает».RESTRICT(по умолчанию): Самый строгий вариант. Пока на клиента есть хоть один заказ — его нихуя нельзя удалить. Сначала разберись с заказами, мудак!
Как это выглядит в лоб, на чистом SQL:
-- Таблица клиентов, родительская. Тут живут папочки.
CREATE TABLE customers (
id INT PRIMARY KEY, -- Главный ключ, он же паспорт
name VARCHAR(255)
);
-- Таблица заказов, дочерняя. Тут живут детки.
CREATE TABLE orders (
id INT PRIMARY KEY,
order_number VARCHAR(50),
customer_id INT, -- Вот это поле будет ссылаться на папочку
-- А вот и сам приказной тон, ограничение!
FOREIGN KEY (customer_id)
REFERENCES customers(id)
ON DELETE SET NULL -- Если папочку удалили, ребёнок остаётся сиротой (NULL)
);
А вот как с этим жить в Go, если ты пользуешься GORM:
GORM — он хитрая жопа, сам многое понимает. Ты просто описываешь структуры, а он уже догадывается, где тут внешний ключ делать.
// Клиент. Может порождать заказы, как кролик.
type Customer struct {
ID uint
Name string
// У одного клиента — дохуя заказов. Связь "один ко многим".
Orders []Order
}
// Заказ. Не может жить без папочки-клиента.
type Order struct {
ID uint
OrderNumber string
// Поле, в котором будет храниться ID папочки. Это и есть внешний ключ в базе.
CustomerID uint
// А это указание для GORM, кто тут папочка. Смотри, блядь, foreignKey:CustomerID — это же твоё же поле выше!
Customer Customer `gorm:"foreignKey:CustomerID"`
}
Запускаешь миграцию — и GORM сам натянет эти связи в базе, создаст ограничения. А если ты попробуешь сохранить заказ с левым CustomerID — получишь ошибку ссылочной целостности прямо в ебало. Красота, блядь! Всё честно, всё по-взрослому.