setval関数でシーケンスの現在値を変更する

PostgreSQLでシーケンスの現在値を変更するには、setval関数を使用する。

SELECT setval('シーケンス名', );

たとえばSERIAL型のidカラムを持つitemsテーブルのシーケンスitems_id_seqを100に設定する場合は以下のように実行する。

SELECT setval('items_id_seq', 100);
 setval
--------
    100
(1 row)

SELECT nextval('items_id_seq');
 nextval
---------
     101
(1 row)

setval実行後にnextvalを呼び出すと、指定した値の次の値(101)が返る。
これはsetvalの第3引数is_calledのデフォルト値がtrueであり、指定した値がすでに払い出し済みとして扱われるためである。

is_calledを指定して次のnextvalで指定値そのものを返す

次にnextvalを呼び出したときに指定値そのものを返したい場合は、第3引数にfalseを指定する。

SELECT setval('items_id_seq', 200, false);
 setval
--------
    200
(1 row)

SELECT nextval('items_id_seq');
 nextval
---------
     200
(1 row)

ALTER SEQUENCE RESTARTでシーケンスの現在値を変更する

ALTER SEQUENCE文のRESTART WITH句でも、シーケンスの現在値を変更できる。

ALTER SEQUENCE items_id_seq RESTART WITH 500;

SELECT nextval('items_id_seq');
 nextval
---------
     500
(1 row)

ALTER SEQUENCE RESTART WITHは、次のnextvalで指定値そのものを返す点がsetvalis_calledのデフォルトtrue)と異なる。

RESTARTに値を指定しない場合は、シーケンスの開始値にリセットされる。
開始値はCREATE SEQUENCEで定義した値(SERIAL型の場合は1)であり、ALTER SEQUENCE ... START WITHで変更していればその値になる。

ALTER SEQUENCE items_id_seq RESTART;

SELECT nextval('items_id_seq');
 nextval
---------
       1
(1 row)

テーブルの最大idにシーケンスを同期する

CSVインポートなどでidを明示的に指定してデータを挿入する場合を考える。
この場合、シーケンスの現在値とテーブルの最大idにずれが生じる。
ずれを解消するには、setvalにテーブルの最大idを渡して同期する。

SELECT setval('items_id_seq', (SELECT MAX(id) FROM items));
 setval
--------
   1000
(1 row)

SELECT nextval('items_id_seq');
 nextval
---------
    1001
(1 row)

setvalis_calledはデフォルトでtrueのため、次のnextvalは最大idの次の値(1001)を返し、主キーの重複を避けられる。

テーブルが空でMAX(id)NULLになる場合、setvalにそのままNULLを渡すと更新されずに終わる。
COALESCE関数でNULLのときの初期値を指定すると、テーブルが空でも安全に実行できる。

SELECT setval('items_id_seq', (SELECT COALESCE(MAX(id), 1) FROM items));

pg_sequencesビューでシーケンスの現在値を確認する

変更後のシーケンスの現在値は、pg_sequencesビューのlast_valueカラムで確認できる。

SELECT sequencename, last_value
FROM pg_sequences
WHERE sequencename = 'items_id_seq';

 sequencename | last_value
--------------+------------
 items_id_seq |       1001
(1 row)