データ型の選定

型は最初の制約

列に型を決めることは、その列に入れてよい値の範囲を決めることです。制約を書く前から、型がすでに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_namedata_type
idinteger
nametext
pricenumeric
is_activeboolean
released_ondate

ヒント

query.sql
学習モード
コードの実行結果
データベースを初期化中...