Пошук уроків, статей та іншого контенту
Визначте унікальний ідентифікатор рядка та зрозумійте вимоги PostgreSQL до первинних ключів.
Первинний ключ (PRIMARY KEY) — це стовпець або набір стовпців, які однозначно ідентифікують кожен рядок таблиці.
Наприклад, у таблиці користувачів кожен користувач може мати унікальний ідентифікатор:
id | name
---+--------
1 | Олена
2 | АндрійУ цьому прикладі стовпець id є первинним ключем:
значення id не повторюються;
значення id не можуть бути NULL;
за значенням id можна однозначно знайти один рядок.
PostgreSQL автоматично застосовує до первинного ключа дві важливі вимоги:
Унікальність — два рядки не можуть мати однакове значення ключа.
Відсутність NULL — первинний ключ завжди має містити значення.
Тому оголошення:
id integer PRIMARY KEYлогічно відповідає такому:
id integer NOT NULL UNIQUEОднак PRIMARY KEY чіткіше передає призначення стовпця: це головний ідентифікатор рядка.
Первинний ключ можна оголосити безпосередньо після типу стовпця:
CREATE TABLE users (
id integer PRIMARY KEY,
name text NOT NULL,
email text NOT NULL
);Тепер PostgreSQL не дозволить додати два рядки з однаковим id:
INSERT INTO users (id, name, email)
VALUES (1, 'Олена', 'olena@example.com');
INSERT INTO users (id, name, email)
VALUES (1, 'Андрій', 'andrii@example.com');Другий INSERT завершиться помилкою, оскільки значення 1 уже використовується первинним ключем.
Також PostgreSQL не дозволить використати NULL:
INSERT INTO users (id, name, email)
VALUES (NULL, 'Марія', 'maria@example.com');Цей запит завершиться помилкою через обмеження NOT NULL.
На практиці ідентифікатор часто генерується автоматично. Для цього можна використати тип GENERATED ALWAYS AS IDENTITY:
CREATE TABLE products (
id integer GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
name text NOT NULL,
price numeric(10, 2) NOT NULL
);
INSERT INTO products (name, price)
VALUES
('Клавіатура', 1499.00),
('Миша', 799.00);
SELECT id, name, price
FROM products;У результаті PostgreSQL сам призначить товарам значення id, наприклад:
id | name | price
---+------------+--------
1 | Клавіатура | 1499.00
2 | Миша | 799.00Під час вставки не потрібно вказувати id, оскільки його створює PostgreSQL.
GENERATED ALWAYS AS IDENTITY гарантує, що значення генеруються базою даних, а не випадково передаються застосунком.
Для первинного ключа можна явно задати ім’я обмеження:
CREATE TABLE orders (
id integer,
created_at date NOT NULL,
CONSTRAINT orders_pkey PRIMARY KEY (id)
);Тут:
orders_pkey — ім’я обмеження;
PRIMARY KEY (id) вказує, що первинним ключем є id.
Якщо ім’я не вказати, PostgreSQL створить його автоматично.
Первинний ключ може складатися з кількох стовпців. Такий ключ називається складеним.
Наприклад, таблиця course_enrollments зберігає записи про зарахування користувачів на курси:
CREATE TABLE course_enrollments (
user_id integer NOT NULL,
course_id integer NOT NULL,
enrolled_at date NOT NULL,
PRIMARY KEY (user_id, course_id)
);У цьому випадку окремо user_id може повторюватися, і окремо course_id може повторюватися. Але їхня комбінація має бути унікальною.
Цей запис дозволений:
INSERT INTO course_enrollments (user_id, course_id, enrolled_at)
VALUES (1, 10, '2026-01-15');
INSERT INTO course_enrollments (user_id, course_id, enrolled_at)
VALUES (1, 20, '2026-01-16');Користувач із user_id = 1 може бути зарахований на кілька курсів.
А цей запис буде відхилено:
INSERT INTO course_enrollments (user_id, course_id, enrolled_at)
VALUES (1, 10, '2026-01-17');Комбінація (1, 10) уже існує в таблиці.
Для таблиць-посередників, які зберігають зв’язки між двома сутностями, складений первинний ключ часто є доречним рішенням.
Якщо таблиця вже існує, первинний ключ можна додати командою ALTER TABLE:
CREATE TABLE categories (
id integer NOT NULL,
name text NOT NULL
);
ALTER TABLE categories
ADD CONSTRAINT categories_pkey PRIMARY KEY (id);Перед додаванням ключа потрібно переконатися, що:
у стовпці немає NULL;
значення не повторюються.
Якщо ці умови порушені, PostgreSQL не зможе створити первинний ключ.
Первинний ключ не лише перевіряє дані. PostgreSQL також створює для нього унікальний індекс, який допомагає ефективно знаходити рядки за ключем.
Наприклад:
SELECT id, name, email
FROM users
WHERE id = 1;Такий запит шукає користувача за унікальним ідентифікатором.
Первинний ключ також часто використовують інші таблиці, щоб посилатися на конкретний рядок. Наприклад, таблиця замовлень може зберігати ідентифікатор користувача. Питання зв’язків між таблицями розглядаються окремо, але важливо запам’ятати: первинний ключ визначає рядок, на який можна посилатися.
Ім’я або електронна адреса можуть здаватися ідентифікаторами, але це залежить від правил предметної області.
Наприклад, якщо імена можуть повторюватися, name не підходить для первинного ключа:
name
-----
Олена
ОленаДля ідентифікації рядків краще використовувати окремий стовпець id.
NULLПервинний ключ не може містити NULL:
CREATE TABLE users (
id integer PRIMARY KEY,
name text
);
INSERT INTO users (id, name)
VALUES (NULL, 'Олена');Такий рядок буде відхилено.
Первинний ключ не допускає повторень:
INSERT INTO users (id, name)
VALUES (1, 'Олена');
INSERT INTO users (id, name)
VALUES (1, 'Андрій');Другий рядок не буде додано.
У таблиці можна мати багато обмежень UNIQUE, але лише один PRIMARY KEY.
Неправильний приклад:
CREATE TABLE users (
id integer PRIMARY KEY,
username text PRIMARY KEY
);Якщо потрібно гарантувати унікальність username, використовуйте окреме обмеження UNIQUE:
CREATE TABLE users (
id integer PRIMARY KEY,
username text UNIQUE NOT NULL
);Тут:
id — первинний ключ;
username — додаткове унікальне поле.
Первинний ключ однозначно ідентифікує рядок таблиці.
Первинний ключ завжди унікальний і не може містити NULL.
У таблиці може бути лише один первинний ключ.
Первинний ключ може складатися з одного або кількох стовпців.
Для автоматичної генерації ідентифікаторів можна використовувати GENERATED ALWAYS AS IDENTITY.
Для додаткових унікальних значень використовуйте UNIQUE, а не другий PRIMARY KEY.