Какие типы ключей (constraints) существуют в SQL?

Ответ

В SQL используются следующие типы ограничений (ключей), которые обеспечивают целостность данных и определяют отношения между таблицами:

1. PRIMARY KEY (Первичный ключ)

  • Уникально идентифицирует каждую запись в таблице
  • Не может содержать NULL значения
  • В таблице может быть только один первичный ключ
  • Часто используется с AUTO_INCREMENT для автоматической генерации значений
CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) NOT NULL
);

2. FOREIGN KEY (Внешний ключ)

  • Создает связь между двумя таблицами
  • Обеспечивает ссылочную целостность (нельзя удалить запись, на которую есть ссылки)
  • Значение должно существовать в связанной таблице или быть NULL
CREATE TABLE orders (
    id INT PRIMARY KEY,
    user_id INT,
    amount DECIMAL(10,2),
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);

3. UNIQUE (Уникальный ключ)

  • Гарантирует уникальность значений в столбце или группе столбцов
  • Отличается от PRIMARY KEY тем, что может содержать NULL значения (в большинстве СУБД только один NULL)
  • В таблице может быть несколько UNIQUE ограничений
CREATE TABLE employees (
    id INT PRIMARY KEY,
    email VARCHAR(100) UNIQUE,  -- Уникальный email
    phone VARCHAR(20) UNIQUE    -- Уникальный телефон
);

4. CHECK (Проверочное ограничение)

  • Проверяет условие перед вставкой или обновлением данных
  • Обеспечивает бизнес-логику на уровне базы данных
CREATE TABLE products (
    id INT PRIMARY KEY,
    price DECIMAL(10,2) CHECK (price > 0),
    quantity INT CHECK (quantity >= 0),
    category VARCHAR(50) CHECK (category IN ('Electronics', 'Books', 'Clothing'))
);

5. NOT NULL (Запрет NULL)

  • Требует, чтобы столбец всегда содержал значение
  • Хотя технически это не "ключ", но важное ограничение целостности
CREATE TABLE customers (
    id INT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    registration_date DATE NOT NULL DEFAULT CURRENT_DATE
);

6. INDEX (Индекс)

  • Хотя индекс не является ограничением в строгом смысле, он часто упоминается вместе с ключами
  • Ускоряет поиск и сортировку, но замедляет вставку и обновление
  • Может быть уникальным (UNIQUE INDEX) или неуникальным
-- Создание индекса для ускорения поиска по email
CREATE INDEX idx_email ON users(email);

-- Составной индекс для поиска по имени и фамилии
CREATE INDEX idx_name ON users(last_name, first_name);

Практический пример с несколькими ограничениями:

CREATE TABLE library_books (
    book_id INT PRIMARY KEY AUTO_INCREMENT,
    isbn VARCHAR(13) UNIQUE NOT NULL,
    title VARCHAR(200) NOT NULL,
    author_id INT NOT NULL,
    published_year INT CHECK (published_year >= 1450 AND published_year <= YEAR(CURDATE())),
    available_copies INT DEFAULT 1 CHECK (available_copies >= 0),

    FOREIGN KEY (author_id) REFERENCES authors(author_id) ON DELETE RESTRICT,
    INDEX idx_title (title),
    INDEX idx_author_year (author_id, published_year)
);

Каждый тип ключа решает конкретную задачу: PRIMARY KEY обеспечивает идентификацию, FOREIGN KEY - связи между таблицами, UNIQUE и CHECK - бизнес-правила, а индексы - производительность.

Ответ 18+ 🔞

А, слушай, вот про SQL ключи рассказывать — это как объяснять, зачем в машине тормоза. Без них поедет, конечно, но потом охуеешь на первом же повороте, когда в дерево врежешься. Так что давай по порядку, а то чувствую, тут удивление пиздец может наступить, если не разобраться.

1. PRIMARY KEY (Первичный ключ) Это типа твой паспорт в таблице. Без него ты — манда с ушами, никто тебя не узнает. Он должен быть уникальным, не может быть пустым (никаких NULL, блядь), и на всю таблицу такой ключ — один, как царь в государстве. Часто его делают с AUTO_INCREMENT, чтобы он сам себе номера придумывал, а ты не парился.

CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) NOT NULL
);

2. FOREIGN KEY (Внешний ключ) Вот это уже связь между таблицами, ёпта. Как верёвка, которая привязывает одну к другой. Нельзя удалить запись в главной таблице, если на неё где-то ссылаются — иначе получится хуй в пальто, данные посыпятся. Либо каскадом удалит всё связанное, либо запретит — как настроишь.

CREATE TABLE orders (
    id INT PRIMARY KEY,
    user_id INT,
    amount DECIMAL(10,2),
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);

3. UNIQUE (Уникальный ключ) Тоже уникальность, но не такая строгая, как у первичного ключа. Может быть NULL (хотя обычно один), и таких ограничений можно навесить овердохуища. Например, чтобы почта или телефон не повторялись у разных людей. А то представь: два чувака с одинаковой почтой — доверия ебать ноль к такой системе.

CREATE TABLE employees (
    id INT PRIMARY KEY,
    email VARCHAR(100) UNIQUE,
    phone VARCHAR(20) UNIQUE
);

4. CHECK (Проверочное ограничение) Это твой внутренний голос, который говорит: «Мужик, не надо так». Проверяет данные перед тем, как их запихнуть в таблицу. Цена не может быть отрицательной, количество товара — меньше нуля, категория должна быть из списка. Короче, бизнес-логика прямо в базе, чтобы с клиентской части не прилетела какая-нибудь хитрая жопа с минусовой ценой.

CREATE TABLE products (
    id INT PRIMARY KEY,
    price DECIMAL(10,2) CHECK (price > 0),
    quantity INT CHECK (quantity >= 0),
    category VARCHAR(50) CHECK (category IN ('Electronics', 'Books', 'Clothing'))
);

5. NOT NULL (Запрет NULL) Технически не ключ, но ограничение важное, бля. Просто говорит: «Это поле должно быть заполнено, идиот». Без имени пользователь? Да похуй, не регистрируйся тогда. Дата регистрации? Ставь текущую автоматом, но пустой не оставляй.

CREATE TABLE customers (
    id INT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    registration_date DATE NOT NULL DEFAULT CURRENT_DATE
);

6. INDEX (Индекс) А вот это магия производительности, ёбать мои старые костыли. Сам по себе не ограничивает данные, но ускоряет поиск по ним в разы. Правда, за это придётся платить: вставка и обновление будут чуть медленнее, потому что индекс тоже надо поддерживать. Но без него на больших таблицах запросы будут идти как черепаха в сиропе — терпения ноль ебать.

CREATE INDEX idx_email ON users(email);
CREATE INDEX idx_name ON users(last_name, first_name);

Ну и пример, где всё вместе, как в хорошем борще:

CREATE TABLE library_books (
    book_id INT PRIMARY KEY AUTO_INCREMENT,
    isbn VARCHAR(13) UNIQUE NOT NULL,
    title VARCHAR(200) NOT NULL,
    author_id INT NOT NULL,
    published_year INT CHECK (published_year >= 1450 AND published_year <= YEAR(CURDATE())),
    available_copies INT DEFAULT 1 CHECK (available_copies >= 0),

    FOREIGN KEY (author_id) REFERENCES authors(author_id) ON DELETE RESTRICT,
    INDEX idx_title (title),
    INDEX idx_author_year (author_id, published_year)
);

Короче, каждый ключ — как инструмент в мастерской. Первичный — это молоток, без него вообще нихуя не соберёшь. Внешний — отвёртка, скрепляет детали. Уникальный и CHECK — это уровень и уголок, чтобы ровно делать. А индексы — это шуруповёрт, чтобы быстрее закручивать. Используй с умом, и база будет летать, а не ползать, как мартышлюшка пьяная.