Ответ
Составной первичный ключ (Composite Primary Key) — это первичный ключ, состоящий из двух или более столбцов таблицы. Уникальность записи обеспечивается только комбинацией значений этих столбцов.
Когда применяется:
- В связующих (junction) таблицах для отношений "многие-ко-многим".
- Когда бизнес-логика определяет сущность уникальной парой/набором атрибутов (например, номер рейса + дата вылета).
Пример на Java с JPA/Hibernate:
// 1. Класс-идентификатор (должен быть Serializable и реализовывать equals/hashCode)
public class EnrollmentId implements Serializable {
private Long studentId;
private Long courseId;
// Конструкторы, геттеры, сеттеры...
@Override
public boolean equals(Object o) { /* сравнение по studentId и courseId */ }
@Override
public int hashCode() { /* хэш-код на основе studentId и courseId */ }
}
// 2. Сущность, использующая составной ключ через аннотацию @IdClass
@Entity
@IdClass(EnrollmentId.class) // Указываем класс-идентификатор
public class Enrollment {
@Id
@Column(name = "student_id")
private Long studentId;
@Id
@Column(name = "course_id")
private Long courseId;
private Integer grade;
private LocalDate enrolledDate;
// Связи с сущностями Student и Course (опционально)
@ManyToOne
@MapsId("studentId") // Связывает с частью ключа
@JoinColumn(name = "student_id", insertable = false, updatable = false)
private Student student;
@ManyToOne
@MapsId("courseId")
@JoinColumn(name = "course_id", insertable = false, updatable = false)
private Course course;
// ...
}
Как это работает в SQL:
CREATE TABLE enrollment (
student_id BIGINT NOT NULL,
course_id BIGINT NOT NULL,
grade INT,
enrolled_date DATE,
PRIMARY KEY (student_id, course_id), -- Составной ключ
FOREIGN KEY (student_id) REFERENCES student(id),
FOREIGN KEY (course_id) REFERENCES course(id)
);
Почему это важно: Гарантирует, что один студент может быть записан на конкретный курс только один раз. Альтернативный подход — использование суррогатного ключа (отдельный id) и уникального ограничения на пару (student_id, course_id).
Ответ 18+ 🔞
А, составной ключ, ёпта! Ну это ж классика, как Муму в мешке, блядь!
Смотри, представь себе таблицу, где один столбец за уникальность не отвечает — нихуя не тянет, один как перст. А вот когда они, сука, объединяются, два или больше, вот тогда они и выдают эту самую уникальную запись. Как Герасим с Муму — по отдельности просто чувак и собачка, а вместе — трагедия на весь мир, блядь.
Где это, сука, пригождается:
- Таблицы-связки для этих ваших «многие-ко-многим». Чтобы студент на один курс дважды не записался, падла такая.
- Когда сама логика бизнеса кричит: «Уникальность вот в этой паре, блядь!». Номер рейса и дата, например. Самолёт же не может в одно и то же время в двух местах быть, если он не хуй с горы, конечно.
Вот тебе пример на Java, смотри, не обосрись:
// 1. Класс-идентификатор. Должен быть Serializable, и equals/hashCode чтоб не хуй собачий был!
public class EnrollmentId implements Serializable {
private Long studentId;
private Long courseId;
// Конструкторы, геттеры, сеттеры...
@Override
public boolean equals(Object o) { /* сравниваем и studentId, И courseId */ }
@Override
public int hashCode() { /* хэш тоже из обоих полей делаем */ }
}
// 2. А вот и сама сущность, хитрая жопа.
@Entity
@IdClass(EnrollmentId.class) // Говорим Хибернейту: «Смотри, чувак, ключ — вот этот класс!»
public class Enrollment {
@Id
@Column(name = "student_id")
private Long studentId; // Первая часть ключа
@Id
@Column(name = "course_id")
private Long courseId; // Вторая часть ключа. Вместе — сила!
private Integer grade; // Оценка
private LocalDate enrolledDate; // Дата записи
// Связи можно прикрутить, но это опционально, блядь
@ManyToOne
@MapsId("studentId") // Эта хуйня связывает связь с частью ключа!
@JoinColumn(name = "student_id", insertable = false, updatable = false)
private Student student;
@ManyToOne
@MapsId("courseId")
@JoinColumn(name = "course_id", insertable = false, updatable = false)
private Course course;
// ...
}
А на SQL это, блядь, выглядит вот так, простота:
CREATE TABLE enrollment (
student_id BIGINT NOT NULL,
course_id BIGINT NOT NULL,
grade INT,
enrolled_date DATE,
PRIMARY KEY (student_id, course_id), -- ВОТ ОН, СОСТАВНОЙ КЛЮЧ, В РОТ МЕНЯ ЧИХ-ПЫХ!
FOREIGN KEY (student_id) REFERENCES student(id),
FOREIGN KEY (course_id) REFERENCES course(id)
);
Суть в чём, блядь? Он гарантирует, что комбинация student_id и course_id будет одна-единственная. Нельзя записать студента дважды на один курс. Можно было бы, конечно, сделать отдельный id (суррогатный ключ) и потом на пару столбцов навесить UNIQUE. Но тут — сразу в лоб, красиво и понятно, как ебалом об асфальт.