Skip to content

Commit 70a9ad5

Browse files
committed
char(n) の注意を強調
1 parent f9809b3 commit 70a9ad5

File tree

1 file changed

+34
-3
lines changed

1 file changed

+34
-3
lines changed

documents/forDB/postgresql_guidelines.md

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -531,8 +531,8 @@ PostgreSQLにはユーザーが使用可能な豊富な[データ型](https://ww
531531
| 文字列 | `varchar(n)` | | | 名称/説明文など。textは桁数が不明となり、システム間連携やデータサイズ見積もりで扱いにくいため、使用しない |
532532
| フラグ | `boolean` || false | 必ず`NOT NULL`制約を付与する。MySQLではbooleanはtinyint型に置き換えられる。tinyintは0と1以外の値を格納することが可能なので、厳密なboolean型を扱うには挿入・更新時に値チェックが必要になることから、MySQLではbooleanの利用は考慮が必要である。PostgreSQLでは上記の問題ないとして推奨する。 フラグの表現として、`char(1)`やsmallintで表現する流派もあるが、入力値が明確になるという点でbooleanを用いる。「boolean型を別の型にできないか考える」章も参考にする |
533533
| UUID | `uuid` | | | `UUID`型か`varchar(36)`の選択があるが、`UUID`型の場合は16byteで済み、性能/コスト上のメリットが大きい。なお、`gen_random_uuid()``UUID`型である |
534-
| 配列 | `[]` | | | 原則、配列は正規化を行い利用しない。もし、利用する場合は`json`/`jsonb`型と同様の利用方針とする。 |
535-
| 構造化データ | `json` `jsonb` | | | 原則JSONデータは正規化を行い、`json`/`jsonb`型は利用しない。 以下のようなユースケースの場合、`json` `jsonb`型の利用を許容する 1️⃣外部のWeb API応答の生データをログ的に保存したい 2️⃣システム間連携で、自システムで利用せず横流しするだけの場合 JSON型は挿入が高速、JSONB型は検索が高速であるため、例えば2️⃣のケースではJSON型を利用する |
534+
| 配列 | `[]` | | | 原則、配列は正規化を行い利用しない。もし、利用する場合は`json`/`jsonb `型と同様の利用方針とする。 |
535+
| 構造化データ | `json` `jsonb` | | | 原則JSONデータは正規化を行い、`json`/`jsonb`型は利用しない。 ただし、次の1、2のような場合は許容する 1️⃣外部のWeb API応答の生データをログ的に保存したい 2️⃣システム間連携で、自システムで利用せず横流しするだけの場合<br> ※JSON型は挿入が高速、JSONB型は検索が高速であるため、例えば2️⃣のケースではJSON型を利用する |
536536

537537
なお、次のデータ型は利用しない。理由は以下。
538538

@@ -542,7 +542,7 @@ PostgreSQLにはユーザーが使用可能な豊富な[データ型](https://ww
542542
- 海外拠点でのアプリケーション利用など、異なるタイムゾーンでの利用時にも対応しやすくなるため
543543
- `char`
544544
- 代わりに `varchar(n)` を用いる
545-
- データサイズの削減メリットがあり、対象のカラム値が最小桁数=最大桁数 である場合に、明示するという目的でも利用をしたい場合がある
545+
- データサイズの削減メリットがあり、対象のカラム値が最小桁数=最大桁数 である場合に、明示するという目的で`char` を利用をしたい場合がある
546546
- テストデータ投入・データパッチ・アプリケーション不備等が原因で、桁不足があると末尾にスペースが入る。それにより動作検証でハマる事が多い
547547
- 本規約では後者の開発生産性観点を優先とし、利用を禁止とする
548548
- `text` および長さの指定がない `varchar`
@@ -569,6 +569,37 @@ PostgreSQLにはユーザーが使用可能な豊富な[データ型](https://ww
569569
整数型はintegerとbigintを使い分けることが本規約の推奨だが、設計の揺れを防ぐためや、考慮漏れなどで`integer` から `bigint` への型変更を完全に避けるために、多少のオーバーヘッドを犠牲に`bigint` に統一する考え方もある。これについては意見が分かれることが多く、採用についてはシステムのワークロードや設計上のトレードオフを考慮して検討すること。
570570
:::
571571

572+
::: warning char(n) 型にハマる
573+
574+
`char(n)` 型はカラム値が桁数未満の場合に、半角スペースでパディングされる仕様がある(桁数超過の場合はエラーになるが、桁数以下の場合はエラーにならない)。
575+
そのため、単体テストデータの比較などで、見た目は正しいが半角スペースの存在で値が不一致となり、テストが落ちてしまうことがある。初心者が良く陥るミスの1つであるが、初見殺しである。
576+
577+
以下に例を示す。
578+
579+
```sql
580+
CREATE TABLE sales_category (
581+
code_id SERIAL PRIMARY KEY,
582+
category_code CHAR(8) -- 固定長8文字
583+
);
584+
585+
-- ダミーデータ登録(5文字)
586+
INSERT INTO sales_category (category_code) VALUES ('DUMMY');
587+
```
588+
589+
SQLで検索すると、表示上は `DUMMY` に見えるが、`CONCAT()` で文字列結合すると `DUMMY 123` と半角スペースでパディングされた値に `123` が追加されていることがわかる。
590+
591+
```sql
592+
# SELECT category_code, CONCAT(category_code, '123') FROM sales_category;
593+
category_code | concat
594+
---------------+-----------
595+
DUMMY | DUMMY 123
596+
(1 row)
597+
```
598+
599+
回避策としては正しく宣言された桁数(先程の例では8文字)でテストデータを登録することが考えられるが、開発者の負荷が高まってしまう。そのため `varchar(n)` を変わりに使い、発生原因を根本から無くすことを推奨する。
600+
601+
:::
602+
572603
参考: [Don't Do This - PostgreSQL wiki](https://wiki.postgresql.org/wiki/Don%27t_Do_This)
573604

574605
## IDENTITY列

0 commit comments

Comments
 (0)