Может ли PRIMARY KEY в SQL быть составным (composite)?

Ответ

Да, PRIMARY KEY может быть составным (composite), то есть состоять из двух или более столбцов таблицы. Уникальность записи в таком случае обеспечивается комбинацией значений этих столбцов.

Пример создания в SQL:

CREATE TABLE OrderItems (
    order_id INT NOT NULL,
    product_id INT NOT NULL,
    quantity INT,
    PRIMARY KEY (order_id, product_id) -- Составной первичный ключ
);

Особенности составного PRIMARY KEY:

  • Уникальность: Комбинация (order_id, product_id) должна быть уникальна.
  • NOT NULL: Все столбцы, входящие в ключ, неявно получают ограничение NOT NULL.
  • Индекс: Создается уникальный индекс по всем столбцам ключа, что ускоряет поиск и операции JOIN.

Реализация в JPA/Hibernate:

  1. С помощью @IdClass:

    @Entity
    @IdClass(OrderItemId.class)
    public class OrderItem {
        @Id private Long orderId;
        @Id private Long productId;
        private Integer quantity;
    }
    
    public class OrderItemId implements Serializable {
        private Long orderId;
        private Long productId;
        // Обязательно переопределить equals() и hashCode()
    }
  2. С помощью @EmbeddedId (часто предпочтительнее):

    @Entity
    public class OrderItem {
        @EmbeddedId
        private OrderItemId id;
        private Integer quantity;
    }
    
    @Embeddable
    public class OrderItemId implements Serializable {
        private Long orderId;
        private Long productId;
        // equals() и hashCode()
    }

Ответ 18+ 🔞

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

Вот смотри, как в SQL это выглядит, чтоб ты не бздел:

CREATE TABLE OrderItems (
    order_id INT NOT NULL,
    product_id INT NOT NULL,
    quantity INT,
    PRIMARY KEY (order_id, product_id) -- Вот он, красавец, составной!
);

А теперь слушай сюда, какие подводные ебучки тут есть:

  • Уникальность, блядь: Теперь пара (order_id, product_id) должна быть одна на весь белый свет. Два одинаковых заказа на один и тот же продукт? Да похуй, не прокатит!
  • NOT NULL: Все столбцы в ключе автоматом становятся обязательными. Хочешь NULL сунуть? Иди нахуй, не выйдет.
  • Индекс: Под эту комбинацию создаётся уникальный индекс, так что поиск и джойны летают, как угорелые.

А в JPA/Hibernate, ёпта, вообще два способа, чтоб мозги не ебать:

  1. Через @IdClass — классика, для старых пердунов:

    @Entity
    @IdClass(OrderItemId.class)
    public class OrderItem {
        @Id private Long orderId;
        @Id private Long productId;
        private Integer quantity;
    }
    
    public class OrderItemId implements Serializable {
        private Long orderId;
        private Long productId;
        // Бля, не забудь equals() и hashCode(), а то всё пиздец накроется!
    }
  2. Через @EmbeddedId — поумнее и почище будет:

    @Entity
    public class OrderItem {
        @EmbeddedId
        private OrderItemId id; // Вот он, весь ключ одним пакетом!
        private Integer quantity;
    }
    
    @Embeddable
    public class OrderItemId implements Serializable {
        private Long orderId;
        private Long productId;
        // И тут тоже equals() с hashCode(), куда без них, блядь?
    }

Вот и вся магия, сука. Не такой уж и страшный зверь, этот составной ключ. Главное — не выёбывайся и делай по правилам, а то Hibernate тебе такую Муму утопит, что мало не покажется!