# Функции nextval и currval

В этой статье рассматриваются функции для работы с последовательностями в рамках одной транзакции, когда в первом запросе добавляется запись в таблицу в базе данных, а в последующих запросах используется ее идентификатор.

## Функция nextval

Функция `nextval` продвигает последовательность к следующему значению и возвращает его. Это атомарная операция: если `nextval` вызывается одновременно в нескольких сеансах, в результате каждого вызова будут гарантированно получены разные значения.

Как правило вызов этой функции указывается в качестве дефолтного значения для первичного ключа. Например, таблица пользователей:

```sql
CREATE TABLE public.user
(
  user_id smallint NOT NULL DEFAULT nextval('user_id_seq'::regclass),
  user_name character varying NOT NULL,
  user_full_name character varying NOT NULL,
  CONSTRAINT pk_user_id PRIMARY KEY (user_id),
  CONSTRAINT unique_by_user_name UNIQUE (user_name)
);
```

{% hint style="warning" %}
Во избежание блокирования параллельных транзакций, пытающихся получить значения одной последовательности, операция `nextval` никогда не откатывается; то есть, как только значение было выбрано, оно считается использованным и не будет возвращено снова. Это утверждение верно, даже когда окружающая транзакция впоследствии прерывается или вызывающий запрос никак не использует это значение.
{% endhint %}

{% hint style="info" %}
Если в качестве типа колонки используется *serial* или *bigserial*, то такие типы автоматически создают последовательности и неявным образом вызывают `nextval,` если при добавлении записи в таблицу полю не задали конкретное значение.
{% endhint %}

## Функция currval

Возвращает значение, выданное при последнем вызове `nextval` для этой последовательности в текущем сеансе. Если в данном сеансе `nextval` ни разу не вызывалась (явно или неявно) для данной последовательности, возвращается ошибка. Так как это значение ограничено рамками сеанса, эта функция выдаёт предсказуемый результат вне зависимости от того, вызвалась ли впоследствии `nextval` в других сеансах или нет.

Рассмотрим использования `currval` на примере добавления нового пользователя:

```xml
<SqlQuery Name="UserInsertSqlQuery">
  <Text>
    INSERT INTO public.user(user_name, user_full_name)
    VALUES({Name}, {FullName});
    
    INSERT INTO template.user(public_user_id)
    VALUES(currval('public.user_id_seq'))
    RETURNING user_id;
  </Text>
</SqlQuery>
```

Так как `nextval`указан в качестве дефолтного значения для колонки user\_id таблицы public.user и в запросе не указывается конкретное значение, то при выполнении команды `INSERT` она сработает автоматически, что позволяет использовать `currval` в следующей команде `INSERT`.

## Значение last\_value

Последовательность хранит свое значение во внутренней таблице. Получить это значение можно через last\_value и SELECT-запрос:

```sql
SELECT last_value FROM user_id_seq;
```

Преимущество такого способа в том, что для получения значения не нужно вызывать `nextval` в том же сеансе. Но значение last\_value *не является потокобезопасным*. Если last\_value будет вызываться в нескольких сеансах одновременно, то во всех сеансах будет использоваться одно и тоже значение, что может нарушить целостность данных.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://wfsys.gitbook.io/wt-knowledge-base/sql/function_nextval_currval.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
