データ型の選定
型は最初の制約
列に型を決めることは、その列に入れてよい値の範囲を決めることです。制約を書く前から、型がすでに1つ目の防壁になっています。
ここでは間違えると後で痛い3つ、金額・日時・真偽値を見ます。
金額に浮動小数を使わない
最もよくある事故がこれです。double precision は2進数で小数を表すので、0.1 を正確に表せません。
SELECT 0.1::float8 + 0.2::float8 = 0.3::float8; -- false足し算の結果が期待した値と一致しません。これが金額の集計で起きると、合計が1円ずれた請求書が出ます。原因を追うのは非常に大変です。
金額に使うのは次の2つです。
| 型 | いつ使うか |
|---|---|
integer | 円のように小数が出ない通貨。最小単位の整数で持つ |
numeric(p, s) | 小数が出る、または桁数を厳密に決めたい場合 |
numeric は10進数のまま計算するので、0.1 + 0.2 は正確に 0.3 になります。速度は浮動小数に劣りますが、金額でずれるより遅いほうが百倍ましです。
日時はタイムゾーン付きで持つ
日時の型は次の3つを使い分けます。
| 型 | 意味 |
|---|---|
date | 日付だけ。注文日、入社日 |
timestamptz | 時点。タイムゾーンを解釈して保存する |
timestamp | タイムゾーンを持たない。原則使わない |
timestamp を使うと、その値が日本時間なのか協定世界時なのかがデータから判断できません。海外の利用者が増えた瞬間に破綻します。時点を表すなら timestamptz、と決めておけば迷いません。
真偽値は boolean
有効フラグを integer の 0 と 1 で持っている設計をよく見ます。boolean があるのに数値で持つと、2 や -1 が入る余地が残ります。
型で表せるものは型で表す。これが物理設計の基本方針です。
文字列は text で始める
PostgreSQL では varchar(n) と text の性能差はありません。桁数の上限に業務上の意味があるとき、たとえば郵便番号や電話番号だけ varchar にして、それ以外は text にします。意味の無い上限は、後で必ず引っかかります。
手を動かす
型の選び方を間違えたテーブルを、ALTER TABLE ... ALTER COLUMN ... TYPE で直します。
テーブル構造
CREATE TABLE products (
id integer PRIMARY KEY,
name text NOT NULL,
price double precision NOT NULL,
is_active integer NOT NULL,
released_on text NOT NULL
);
INSERT INTO products VALUES
(1, 'ノートPC', 128000, 1, '2026-01-15'),
(2, 'マウス', 3200, 1, '2026-02-01'),
(3, '旧型キーボード', 5800, 0, '2024-11-20');
期待される出力
| column_name | data_type |
|---|---|
| id | integer |
| name | text |
| price | numeric |
| is_active | boolean |
| released_on | date |