автоинкремент postgres не обновляется при вставке явных идентификаторов - PullRequest
44 голосов
/ 02 февраля 2012

У меня есть следующая таблица в postgres:

CREATE TABLE "test" (
    "id" serial NOT NULL PRIMARY KEY,
    "value" text
)

Я делаю следующие вставки:

insert into test (id, value) values (1, 'alpha')
insert into test (id, value) values (2, 'beta')

insert into test (value) values ('gamma')

В первых 2 вставках я явно упоминаю идентификатор. Однако указатель автоматического увеличения таблицы в этом случае не обновляется. Следовательно в 3-й вставке я получаю ошибку:

ERROR:  duplicate key value violates unique constraint "test_pkey"
DETAIL:  Key (id)=(1) already exists.

Я никогда не сталкивался с этой проблемой в Mysql как в движках MyISAM, так и в INNODB. Явно или нет, mysql всегда обновляет указатель автоинкремента на основе максимального идентификатора строки.

Какой обходной путь для этой проблемы в postgres? Мне это нужно, потому что я хочу более жесткий контроль для некоторых идентификаторов в моей таблице.

UPDATE: Мне это нужно, потому что для некоторых значений мне нужно иметь фиксированный идентификатор. Для других новых записей я не против создания новых.

Я думаю, что это возможно, вручную увеличивая указатель nextval до max(id) + 1 всякий раз, когда я явно вставляю идентификаторы. Но я не уверен, как это сделать.

Ответы [ 2 ]

79 голосов
/ 02 февраля 2012

Вот как это должно работать - next_val('test_id_seq') вызывается только тогда, когда системе нужно значение для этого столбца, а вы его не указали. Если вы указываете значение, такой вызов не выполняется и, следовательно, последовательность не «обновляется».

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

SELECT setval('test_id_seq', (SELECT MAX(id) from "test"));
3 голосов
/ 03 октября 2018

В последней версии Django эта тема обсуждается в документации:

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

Ссылка: https://docs.djangoproject.com/en/dev/ref/databases/#manually-specified-autoincrement-pk

Существует также команда управления manage.py sqlsequencereset app_label ..., которая может генерировать операторы SQL для сброса последовательностей для заданных имен приложений

Ссылка: https://docs.djangoproject.com/en/dev/ref/django-admin/#django-admin-sqlsequencereset

Например, эти операторы SQL были сгенерированы manage.py sqlsequencereset my_app_in_my_project:

BEGIN;
SELECT setval(pg_get_serial_sequence('"my_project_aaa"','id'), coalesce(max("id"), 1), max("id") IS NOT null) FROM "my_project_aaa";
SELECT setval(pg_get_serial_sequence('"my_project_bbb"','id'), coalesce(max("id"), 1), max("id") IS NOT null) FROM "my_project_bbb";
SELECT setval(pg_get_serial_sequence('"my_project_ccc"','id'), coalesce(max("id"), 1), max("id") IS NOT null) FROM "my_project_ccc";
COMMIT;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...