web-dev-qa-db-ja.com

明示的なID挿入でpostgres自動インクリメントが更新されない

私は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つの挿入では、IDを明示的に言及しています。ただし、この場合、テーブルの自動インクリメントポインタは更新されません。したがって、3番目の挿入でエラーが発生します。

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

MyISAMエンジンとINNODBエンジンの両方のMysqlでこの問題に直面したことはありません。明示的かどうかにかかわらず、mysqlは常に最大行IDに基づいて自動インクリメントポインタを更新します。

Postgresでのこの問題の回避策は何ですか?テーブルの一部のIDをより厳密に制御したいので、これが必要です。

PDATE:一部の値には固定IDが必要なため、これが必要です。他の新しいエントリについては、新しいエントリを作成してもかまいません。

IDを明示的に挿入しているときはいつでも、手動でnextvalポインタをmax(id) + 1にインクリメントすることで可能になると思います。しかし、それを行う方法はわかりません。

55
jerrymouse

これが機能する方法です。next_val('test_id_seq')が呼び出されるのは、システムがこの列の値を必要とし、ユーザーが値を提供していない場合のみです。値を指定すると、そのような呼び出しは実行されないため、シーケンスは「更新」されません。

あなたは手動でこれを回避することができます setting 明示的に提供された値で最後の挿入後のシーケンスの値:

SELECT setval('test_id_seq', (SELECT MAX(id) from "test"));
83
Milen A. Radev

Djangoの最近のバージョンでは、このトピックはドキュメントで説明されています。

DjangoはPostgreSQLの SERIALデータ型 を使用して、自動インクリメントの主キーを格納します。 SERIAL列には、次に利用可能な値を追跡する sequence の値が入力されます。自動インクリメントフィールドに手動で値を割り当てても、フィールドのシーケンスは更新されず、後で競合が発生する可能性があります。

Ref:https://docs.djangoproject.com/en/dev/ref/databases/#manually-specified-autoincrement-pk

指定されたアプリ名のシーケンスをリセットするためのSQLステートメントを生成できる管理コマンドmanage.py sqlsequencereset app_label ...もあります。

Ref: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;
3
illagrenan