Подтвердить что ты не робот

PostgreSQL следующее значение последовательностей?

Я использую PostgreSQL для моего сайта Codeigniter. Я использую groqery crud для добавления, редактирования и удаления операций. Во время редактирования или добавления я хочу динамически переименовать загруженный файл на основе идентификатора содержимого. Я могу сделать это, используя функцию бакалеи crud callback_after_upload.

Я хочу следующий идентификатор содержимого при добавлении нового контента. Я попытался использовать функцию nextval(), но последовательность с ней увеличивается. Как получить последнее значение последовательности без использования функции nextval()?

Или есть простой способ, которым я могу это сделать?

4b9b3361

Ответ 1

RETURNING

В современном PostgreSQL (8.2 или новее) вы делаете это с одним обращением к базе данных:

INSERT INTO tbl(filename)
VALUES ('my_filename')
RETURNING tbl_id;

tbl_id является serial. Подробнее в руководстве.

Явное извлечение значения

Если filename необходимо включить tbl_id (избыточно), вы все равно можете использовать один запрос.
Используйте lastval() или более конкретный currval():

INSERT INTO tbl (filename)
VALUES ('my_filename' || lastval())  -- or currval('tbl_tbl_id_seq')
RETURNING tbl_id;

Руководство по lastval():

Эта функция идентична currval, за исключением того, что вместо имя последовательности в качестве аргумента, которое выдает значение последнего последовательность, используемая nextval в текущем сеансе.

Если у вас есть (или может быть) несколько последовательностей, связанных с таблицей (даже с помощью триггеров или других побочных эффектов), верный способ - использовать currval('tbl_tbl_id_seq').

Название последовательности

Строковый литерал 'tbl_tbl_id_seq' в моем примере должен быть фактическим именем последовательности и отбрасывается в regclass, что вызывает исключение, если в текущем search_path.

tbl_tbl_id_seq - автоматически созданный по умолчанию для таблицы tbl с последовательным столбцом tbl_id. Но никаких гарантий нет. По умолчанию столбцы могут извлекать значения из любой последовательности, если они определены. И если при создании таблицы берется имя по умолчанию, Postgres выбирает следующее свободное имя в соответствии с жестко запрограммированным алгоритмом.

Если вы не знаете имя последовательности для столбца serial, найдите ее с помощью выделенной функции pg_get_serial_sequence(). Можно даже сделать "на лету":

INSERT INTO tbl (filename)
VALUES ('my_filename' || currval(pg_get_serial_sequence('tbl', 'tbl_id'))
RETURNING tbl_id;

SQL Fiddle.

Ответ 2

Доступ к ранее полученному значению последовательности осуществляется с помощью функции currval().

Но это только вернет значение, если nextval() было вызвано до, что.

Нет абсолютно никакого способа "подглядывать" при следующем значении последовательности без фактического ее получения.

Но ваш вопрос непонятен. Если вы вызываете nextval() перед выполнением вставки, вы можете использовать это значение во вставке. Или еще лучше, используйте currval() в инструкции insert:

select nextval('my_sequence') ...

... do some stuff with the obtained value

insert into my_table(id, filename)
values (currval('my_sequence'), 'some_valid_filename');

Ответ 3

Даже если это можно как-то сделать, это ужасная идея, так как можно было бы получить последовательность, которая затем будет использоваться другой записью!

Гораздо лучшая идея состоит в том, чтобы сохранить запись и затем получить последовательность после этого.

Ответ 4

Если у вас нет сеанса, вы можете просто nextval ('you_sequence_name'), и это просто отлично.

Ответ 5

Чтобы ответить на ваш вопрос буквально, вот как получить следующее значение последовательности, не увеличивая ее:

SELECT
 CASE WHEN is_called THEN
   last_value + 1
 ELSE
   last_value
 END
FROM sequence_name

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

Ответ 6

Я пробовал это, и он отлично работает

@Entity
public class Shipwreck {
  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq")
  @Basic(optional = false)
  @SequenceGenerator(name = "seq", sequenceName = "shipwreck_seq", allocationSize = 1)
  Long id;

....

CREATE SEQUENCE public.shipwreck_seq
    INCREMENT 1
    START 110
    MINVALUE 1
    MAXVALUE 9223372036854775807
    CACHE 1;