Раздел 33 · PostgreSQL с нуля

Автонумерация: serial и identity

junior~20 мин

без входаВойди, чтобы отмечать прогресс, вести заметки и решать задачи в редакторе. войти

В прошлом уроке мы вставляли книги с номерами 1, 2, 3, написанными руками. Пока магазином пользуешься один, это работает. Но когда заказы оформляют сто покупателей одновременно, каждому нужен свой номер, и раздавать их должен кто-то один. В PostgreSQL этим занимается база.

Аппарат с талончиками

Вспомни аппарат электронной очереди в банке. Нажимаешь кнопку, получаешь талон 47. Следующий человек получает 48. Аппарат не спрашивает, свободен ли номер, он помнит последний выданный и прибавляет единицу. Двое людей не получат один номер, даже если нажмут кнопку одновременно.

А если ты взял талон 49 и ушёл, не дождавшись очереди? Номер 49 никто больше не получит. Аппарат назад не крутит. Запомни этот момент, он ещё пригодится.

В PostgreSQL такой аппарат называется последовательностью. Это отдельный объект в базе, и создать его можно руками:

CREATE SEQUENCE ticket_seq;

SELECT nextval('ticket_seq');
SELECT nextval('ticket_seq');
SELECT currval('ticket_seq');
 nextval
---------
       1

 nextval
---------
       2

 currval
---------
       2

nextval нажимает кнопку и выдаёт следующий номер. currval показывает, какой номер последним получила твоя сессия, ничего не выдавая.

Руками последовательности почти никогда не трогают. Их создают за тебя два механизма: старый serial и новый identity.

serial: старый способ

CREATE TABLE authors (
  id   serial PRIMARY KEY,
  name text NOT NULL
);

serial выглядит как тип, но это сокращение. Postgres разворачивает его в три вещи: колонку integer, последовательность authors_id_seq и значение по умолчанию nextval('authors_id_seq'). Если открыть описание таблицы командой \d authors в psql, это видно:

 Column |  Type   | Collation | Nullable |               Default
--------+---------+-----------+----------+-------------------------------------
 id     | integer |           | not null | nextval('authors_id_seq'::regclass)
 name   | text    |           | not null |

Значение по умолчанию подставляется, только когда ты не указал id сам. А указать его никто не запрещает. Отсюда классическая авария:

INSERT INTO authors (name) VALUES ('Адитья Бхаргава'), ('Максим Ильяхов');
INSERT INTO authors (id, name) VALUES (3, 'Стив Макконнелл');
INSERT INTO authors (name) VALUES ('Роберт Мартин');
ERROR:  duplicate key value violates unique constraint "authors_pkey"
DETAIL:  Key (id)=(3) already exists.

Первые два автора получили 1 и 2 из последовательности. Третьего вставили с номером 3 руками, в обход аппарата. Аппарат об этом не знает и четвёртому автору честно выдаёт 3, которое уже занято. На практике так ломаются базы после ручного импорта данных: все вставки падают, пока последовательность не подвинут.

урок из курса

Урок из курса «PostgreSQL с нуля». Курс покупается один раз и остаётся навсегда: 500 ₽.

Оплата пока не подключена: премиум и курсы открываются промокодом.