PostgreSQLのシーケンスのnextvalの挙動

この記事はPostgreSQL9.4をベースに書いています。

`create sequence` で `start with 1` と指定すると、最初に `nextval()` した時に `1` が返ってくる。

```sql:
mydb=# create sequence hoge start with 1;
CREATE SEQUENCE

mydb=# select nextval('hoge');
 nextval
---------
       1
(1 row)
```

ここまでは良くて、次に値をリセットしたくて `setval('hoge',1)` した後で `nextval('hoge')` すると `2` が返ってきてファッ!?となった。

```sql:
mydb=# select setval('hoge',1);
 setval
--------
      1
(1 row)

mydb=# select nextval('hoge');
 nextval
---------
       2
(1 row)
```

それならばと、`0` をセットしてみるが、範囲外と怒られてしまう。

```sql:
mydb=# select setval('hoge',0);
ERROR:  setval: value 0 is out of bounds for sequence "hoge" (1..9223372036854775807)
```

それぞれの状態を調べてみると、create sequenceした直後は `is_called` の値が `false` だが、 `setval` した直後は `true` なようだ。

```sql:create_sequnceした直後
mydb=# select * from hoge;
 sequence_name | last_value | start_value | increment_by |      max_value      | min_value | cache_value | log_cnt | is_cycled | is_called
---------------+------------+-------------+--------------+---------------------+-----------+-------------+---------+-----------+-----------
 hoge          |          1 |           1 |            1 | 9223372036854775807 |         1 |           1 |       0 | f         | f
(1 row)

```

```sql:setvalした直後
mydb=# select * from hoge;
 sequence_name | last_value | start_value | increment_by |      max_value      | min_value | cache_value | log_cnt | is_cycled | is_called
---------------+------------+-------------+--------------+---------------------+-----------+-------------+---------+-----------+-----------
 hoge          |          1 |           1 |            1 | 9223372036854775807 |         1 |           1 |       0 | f         | t
(1 row)

```

`create sequence` は、`nextval()` したタイミングで `is_called` が `true` になるようだ。

```sql:
mydb=# create sequence hoge start with 1;
CREATE SEQUENCE

mydb=# select nextval('hoge');
 nextval
---------
       1

mydb=# select * from hoge;
 sequence_name | last_value | start_value | increment_by |      max_value      | min_value | cache_value | log_cnt | is_cycled | is_called
---------------+------------+-------------+--------------+---------------------+-----------+-------------+---------+-----------+-----------
 hoge          |          1 |           1 |            1 | 9223372036854775807 |         1 |           1 |      32 | f         | t
(1 row)

mydb=# select nextval('hoge');
 nextval
---------
       2
(1 row)
```

[調べたら](https://www.postgresql.jp/document/9.4/html/functions-sequence.html)、`setval` には第3引数に `is_called` が指定できるようだ。デフォルトが `true` なのは `select setval('hoge', select MAX(id) from huga);` とかする時はその方が良いからかな。

```sql
mydb=# select setval('hoge',1,false);
 setval
--------
      1
(1 row)

mydb=# select nextval('hoge');
 nextval
---------
       1
(1 row)
```


`alter sequence restart with` しても `is_called` には `false` が設定されるようだ。忘れた頃に `setval` してハマる気がするので今後はこっち使うようにした方が良いかな。

```sql
mydb=# alter sequence hoge restart with 1;
ALTER SEQUENCE
mydb=# select * from hoge;
 sequence_name | last_value | start_value | increment_by |      max_value      | min_value | cache_value | log_cnt | is_cycled | is_called
---------------+------------+-------------+--------------+---------------------+-----------+-------------+---------+-----------+-----------
 hoge          |          1 |           1 |            1 | 9223372036854775807 |         1 |           1 |       0 | f         | f
(1 row)

mydb=# select nextval('hoge');
 nextval
---------
       1
(1 row)
```