Skip to content

Commit

Permalink
Merge pull request #1427 from future-architect/feature
Browse files Browse the repository at this point in the history
追記
  • Loading branch information
ma91n authored Nov 13, 2024
2 parents f861b4d + c0e9455 commit fc99af5
Showing 1 changed file with 156 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ Technology Innovation Group真野です。

- 新規構築なら連番の自動採番はSERIAL/BIGSERIALの代わりに `GENERATED ALWAYS AS IDENTITY` の利用がベター
- DEFAULTキーワードは利用せず、省略する
- 暗黙的に作成されるシーケンスは、テーブル名やカラム名のリネームに追随しないので、合わせてリネームする運用にする
- 気になった部分の調査事項と結果は下表

| 調査項目 | 結果 |
Expand All @@ -39,6 +40,10 @@ Technology Innovation Group真野です。
| パーティションテーブルでの利用 | 利用できる |
| 作成されたシーケンスの名称 | {テーブル名}_{カラム名}_seq |
| 作成されたシーケンスを削除したらどうなるか | 削除不可 |
| シーケンス名の上限63文字を超過したテーブル、カラム名の場合 | それぞれ29文字上限でオミットされて生成 |
| テーブル名を変更した時シーケンス名はどうなるか | 変化なし |
| カラム名をを変更した時シーケンス名はどうなるか | 変化なし |
| 独自に作成したシーケンスとの紐づけ方法 | できない |
| 文字列型とGENERATED AS IDENTITYの組み合わせ| 設定不可 |
| SERIAL型とGENERATED AS IDENTITYの組み合わせ | 設定不可 |

Expand All @@ -53,6 +58,19 @@ CREATE TABLE color (
);
```

テーブルの状態は以下です。`GENERATED AS IDENTITY` を付けると暗黙的にNOT NULL制約がつくことも分かります。

```sql
postgres-# \d color;
Table "public.color"
Column | Type | Collation | Nullable | Default
------------+-------------------+-----------+----------+----------------------------------
color_id | bigint | | not null | generated by default as identity
color_name | character varying | | not null |
Indexes:
"color_pkey" PRIMARY KEY, btree (color_id)
```

このテーブルで`color_id` を未指定にして、2件データを登録します。

```sql
Expand Down Expand Up @@ -358,6 +376,23 @@ WHERE
(1 row)
```

上記のSQLは少し長いので、 `pg_get_serial_sequence(table text, column text)` というシステムカタログ情報関数も用意されています。

- https://www.postgresql.jp/document/16/html/functions-info.html#FUNCTIONS-INFO-CATALOG

```sql
SELECT pg_get_serial_sequence('color', 'color_id') AS sequence_name;
```

結果です。

```sql
sequence_name
---------------------------
public.color_color_id_seq
(1 row)
```

### 5. 作成されたシーケンスを削除したらどうなるか

誤ってIDENTITY列が内部的に使用するシーケンスオブジェクトを削除したら、不正な状態にならないかテストです。当然、失敗します。
Expand All @@ -370,7 +405,126 @@ HINT: You can drop column color_id of table color instead.

もし、このシーケンスを削除したい場合は、colorテーブルのcolor_id列を削除する必要があるとあります。妥当なメッセージです。

### 6. 文字列型とGENERATED BY DEFAULT AS IDENTITYの組み合わせ
### 6. シーケンス名の上限63文字を超過したテーブル、カラム名の場合

PostgreSQLではシーケンスに限らず、識別子の最長は63文字です。

- https://www.postgresql.jp/document/16/html/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS

そのため、IDENTITYで自動で生成されるシーケンス名の体系が、{テーブル名}_{カラム名}_seq だとすると、超過した場合にどう命名されるか気になりました。

試してみます。テーブル名が36文字、カラム名が39文字です。

```sql
CREATE TABLE looooooooooooooooooooooooooooooooong (
looooooooooooooooooooooooooooooooong_id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
color_name VARCHAR NOT NULL
);
```

シーケンス名を確認すると、次の結果となりました。

```sql
postgres=# SELECT pg_get_serial_sequence('looooooooooooooooooooooooooooooooong', 'looooooooooooooooooooooooooooooooong_id') AS sequence_name;
sequence_name
------------------------------------------------------------------------
public.loooooooooooooooooooooooooooo_loooooooooooooooooooooooooooo_seq
```

テーブル名、カラム名が長いと最長で29文字で前方からオミットされて生成されるようです。

直接シーケンス名を指定して `setval()` するときに困ることが多いかなと思いますので、注意が必要です。

### 7. テーブル名を変更した時シーケンス名はどうなるか

シーケンス名は自動生成されますが、ALTERでテーブル名を変えた場合にどうなるか確かめます。

```sql
ALTER TABLE looooooooooooooooooooooooooooooooong RENAME TO color;
```

結果は以下の通り、変化無しです。

```sql
postgres=# SELECT pg_get_serial_sequence('color', 'looooooooooooooooooooooooooooooooong_id') AS sequence_name;
sequence_name
------------------------------------------------------------------------
public.loooooooooooooooooooooooooooo_loooooooooooooooooooooooooooo_seq
(1 row)
```

そのため、テーブル名を変更した場合は、シーケンス名もリネームするような運用を行った方が良いでしょう。

### 8. カラム名をを変更した時シーケンス名はどうなるか

7と同様に、カラム名を変更した場合にシーケンス名がどうなるか確認します。

```sql
ALTER TABLE color RENAME COLUMN looooooooooooooooooooooooooooooooong_id TO color_id;
```

結果は以下の通り、テーブル名と同様、カラム名の変更も変化ありません。

```sql
postgres=# SELECT pg_get_serial_sequence('color', 'color_id') AS sequence_name;
sequence_name
------------------------------------------------------------------------
public.loooooooooooooooooooooooooooo_loooooooooooooooooooooooooooo_seq
(1 row)
```

結論も7と同様、テーブル名/カラム名が変更した場合は、シーケンス名もリネームする運用を行うとベターでしょう。

```sql シーケンスのリネーム
ALTER SEQUENCE loooooooooooooooooooooooooooo_loooooooooooooooooooooooooooo_seq RENAME TO color_color_id_seq;
```

### 9. 独自に作成したシーケンスとの紐づけ方法

SERIAL型であれば、以下のように指定すると独自のシーケンスと紐づけることができました。

```sql
-- 独自シーケンス
CREATE SEQUENCE custom_color_seq;

-- DEAULTでシーケンスと紐づける
CREATE TABLE color (
color_id BIGINT NOT NULL DEFAULT nextval('custom_color_seq') PRIMARY KEY,
color_name VARCHAR NOT NULL
);
ALTER SEQUENCE custom_color_seq OWNED BY color.color_id;
```

BIGINTを指定していて、BIGSERIALを使っていないじゃない?と思うかもしれません。しかし[ドキュメント](https://www.postgresql.jp/docs/16/datatype-numeric.html#DATATYPE-SERIAL)にも記載通り、以下の2つの構文は同義ですので、これが言えます。

```sql
CREATE TABLE tablename (
colname SERIAL
);
```

```sql SERIAL型の裏側
CREATE SEQUENCE tablename_colname_seq AS integer;
CREATE TABLE tablename (
colname integer NOT NULL DEFAULT nextval('tablename_colname_seq')
);
ALTER SEQUENCE tablename_colname_seq OWNED BY tablename.colname;
```

IDENTITY列に関しては、手動で作成したシーケンスとIDENTITY列を紐づける構文は、ドキュメントを探した時点では存在しませんでした。

そのため、独自の名称のシーケンスにしたければ `ALTER SEQUENCE RENAME` で変更する運用になるかと思います。

また、次のようにシーケンスオプションも作成時に指定できます(ALTERで変更も可能)です。おそらく、困ることは無いかなと思います。

```sql
CREATE TABLE color (
color_id INT GENERATED ALWAYS AS IDENTITY (START WITH 10 INCREMENT BY 1 CACHE 100),
color_name VARCHAR NOT NULL
);
```

### 10. 文字列型とGENERATED BY DEFAULT AS IDENTITYの組み合わせ

文字列型(text型)にGENERATED ALWAYS AS IDENTITYを指定すると、いい感じの型変換により '1'、'2'、...といった採番がされないかと思いついたので試しました。

Expand All @@ -384,7 +538,7 @@ ERROR: identity column type must be smallint, integer, or bigint

無事エラーで、これは対応していないようです。型としては、`smallint` `integer` `bigint` のみ対応。

### 7. SERIAL型とGENERATED BY DEFAULT AS IDENTITYの組み合わせ
### 11. SERIAL型とGENERATED BY DEFAULT AS IDENTITYの組み合わせ

SERIAL型であれば、型としては `integer` 型なので、いけるのではと一応チャレンジしました。結果は以下のエラーです。

Expand Down

0 comments on commit fc99af5

Please sign in to comment.