Генераторы последовательностей. SEQUENCE
Дорогу осилит идущийВ рамках этого урока познакомимся с простым, но важным для целостной картины, механизмом последовательностей (они же - sequence). Касаясь PostgreSQL, именно на этом механизме основаны инкрементирующиеся типы данных вроде bigserial - именно последовательности обеспечивают увеличение значения.
Прежде чем приступим к разбору синтаксиса, подсвечу несколько моментов:
- Изменения последовательностей не откатываются при неудачной транзакции. Из-за этого могут быть разрывы в порядке числовых id, если он представлен serial-типов или в иных случаях, когда столбец наполняется значением последовательности. Иногда это может иметь значение - например, если последовательность наполняет номера или иные атрибуты, которые должны идти строго по порядку. Например, номер документа/договора/протокола и пр. в зависимости от домена разрабатываемой системы. В таких случаях может потребоваться механизм программной установки значения после сброса или же вообще отказ от последовательности и замены его на иной механизм с похожей функциональностью;
- Стоит уточнять механизм взаимодействия последовательностей и оператора TRUNCATE (или же, используется ли в механизме получения id именно последовательность, а не иной механизм) - например, PostgreSQL не сбрасывает значение при вызове TRUNCATE-запроса для таблицы, но другие СУБД могут обнулять счетчик автоматически - скажем, это актуально для MySQL;
- Sequence является одним из возможных вариантов получения уникального в рамках своей зоны ответственности значения - это может быть актуально для распределенных систем, если мы не можем обеспечить уникальность числового значения средствами приложения, а UUID или иные генераторы уникальных значений не могут быть использованы в силу иных причин. В таком случае точкой синхронизации для параллельно работающих частей системы может выступить СУБД, а инструментом получения уникального значения - последовательность.
Синтаксис
Sequence определен в стандарте SQL и в рамках DDL имеет достаточно стандартный синтаксис. Впрочем, как и с остальными сущностями, конкретная СУБД может иметь свои особенности. Поэтому предложенный синтаксис актуален, в первую очередь, для PostgreSQL. При работе с иными СУБД рекомендую дополнительно проверить возможные отличия.
Создание последовательности:
create sequence sequence_name;
В базовом варианте достаточно указать название последовательности. Такой запрос создаст sequence с шагом изменения равным 1, начальным значением также будет 1, конечным - 2^63-1.
Эти параметры являются настраиваемыми. Например, создадим последовательность от 0 до 10000 с шагом 10:
create sequence limited_sequence increment by 10 minvalue 0 maxvalue 10000;
Кроме того, мы можем зациклить последовательность, чтобы после достижения максимального значения последовательность начинала выдачу значений сначала. Если этого не сделать, после достижения максимального значения при каждой попытке получить следующее - будет ошибка. В зависимости от применения последовательности, будет отличаться и корректность применения зацикленности:
create sequence limited_sequence_cycle increment by 10 minvalue 0 maxvalue 10000 cycle;
Также можно сделать убывающую последовательность - для этого нужно указать отрицательный шаг изменения. При этом минимальным значением по умолчанию станет -1, а максимальным - 2^63-1. Но все также можно будет задать эти значения явно.
Удаление последовательности тоже выглядит стандартно:
drop sequence sequence_name;
И, наконец, используя ALTER можно изменить шаг, минимальное и максимальное значения последовательности и несколько иных, не критичных на данном этапе, параметров.
Кроме того, именно через ALTER можно перезапустить последовательность (сбросить текущее значение и начать снова с минимального):
alter sequence limited_sequence restart;
Или с заданного явно:
alter sequence limited_sequence restart with 25;
И бонусный пример - установка минимального значения выше текущего:
alter sequence limited_sequence minvalue 100 start 100;
В данном случае, без start была бы ошибка: начало (было 0 (нуль)) не может быть ниже минимального значения для возрастающей последовательности.
Теперь немного о том, как запросить значение из последовательности и иных функциях для работы с sequence.
Текущее (точнее, последнее возвращенное) значение последовательности на примере limited_sequence:
select currval('limited_sequence');
Обратите внимание на оговорку выше. Если вы вызовете RESTART с начального значения, функция currval() все равно вернет последнее полученное значение, а не начальное для данной последовательности.
Очевидно, функцию (как и другие), можно применять в любом запросе, а не только в SELECT.
Получить новое (следующее) значение:
select nextval('limited_sequence');
И, наконец, установить текущее значение явно:
select setval('limited_sequence', 140);
В отличии от рестарта последовательности, использование setval() сохранит заявленное значение и для currval().
Кроме того, для setval() существует перегрузка: считать заданное значение следующим (для вызова nextval()):
select setval('limited_sequence', 140, false);
или последним использованным (идентично вызову без булеан-параметра):
select setval('limited_sequence', 140, true);
Чуть подробнее: https://postgrespro.ru/docs/postgresql/9.6/functions-sequence
На сегодня все!
Не вижу смысла в практике для данной темы - она достаточно простая и ее синтаксис не выходит за пределы общих правил, знакомых нам по DDL-разделу.

Если что-то непонятно или не получается – welcome в комменты к посту или в лс:)
Канал: https://t.me/ViamSupervadetVadens
Мой тг: https://t.me/ironicMotherfucker
Дорогу осилит идущий!