CHAPTER 04読む目安 15分主キー・外部キー・NULL を請求書の例で

テーブルとデータ型

この章のゴール:テーブルの列には「型」があること、行を一意に見分ける主キー、テーブル同士をつなぐ外部キー、空欄を表すNULLの意味を説明できる。

テーブルは「列の設計」がすべて

Excelでは、どのセルに何を入れても構いません。A列に会社名、B列に金額を入れるつもりでも、間違えて逆に入れてもExcelは何も言いません。

データベースのテーブルは違います。テーブルを作るとき、「どんな列があり、それぞれにどんな種類の値を入れるか」を先に決め、その約束に合わない値は受け付けません。この約束のことをテーブルの定義、列ごとの「値の種類」のことをデータ型と呼びます。

みなと文具の得意先テーブルを、PostgreSQLの言葉で定義すると次のようになります。今は「読める」ことが目標なので、書けなくて構いません。

-- 得意先テーブルを作る
CREATE TABLE customers (
  code        char(4)       PRIMARY KEY,   -- 得意先コード(4文字、重複不可)
  name        text          NOT NULL,      -- 会社名(必須)
  pref        text,                        -- 都道府県(空欄でもよい)
  credit_limit numeric(12,0),             -- 与信限度額(円)
  created_at  date          NOT NULL       -- 登録日
);

1行ずつ見ると「列の名前」「データ型」「追加の決まりごと」の3つが並んでいるだけです。それぞれ説明します。

データ型:列に入れてよい値の種類

PostgreSQLには数十種類のデータ型がありますが、最初に知っておきたいのは次の6つです。

データ型入れられる値使いどころ
integer整数(約±21億まで)個数、連番
numeric桁数を指定できる正確な数金額。小数の誤差が出ないため、お金は必ずこの型を使う
text / varchar(n)文字列(varcharは最大文字数を決める)名前、住所、メモ
date日付請求日、登録日
timestamp日付+時刻更新された日時の記録
boolean真(true)か偽(false)「取引中かどうか」のような二択
経理の人がよく驚く点

金額に integer や、小数を扱う float(浮動小数点)という型を使うと、消費税の計算などで1円の誤差が出ることがあります。お金の列は numeric を使うのがデータベース設計の鉄則です。「金額の列の型が何か」は、経理担当がシステム部門に確認する価値のある質問です。

主キー:行を一意に見分ける札

PRIMARY KEY(主キー、プライマリキー)は、その行を他のすべての行と確実に区別するための列です。得意先テーブルなら得意先コード、請求書テーブルなら請求書番号がこれにあたります。

主キーには2つの約束が自動的につきます。

  • 重複しない:同じ得意先コードの行を2つ作ろうとすると、PostgreSQLがエラーにして拒否します。第1章の「同じ会社が2行登録されてしまう」問題は、これで防げます。
  • 空欄にできない:コードが入っていない得意先は登録できません。

会社名を主キーにしないのは、社名変更や同名の会社があり得るためです。「変わらず、重ならない」コードや番号を主キーにするのが基本です。

外部キー:テーブルとテーブルをつなぐ糸

第1章で「請求書には会社名を書かず、得意先コードだけを書く」と説明しました。請求書テーブルの定義を見てみましょう。

CREATE TABLE invoices (
  id          integer       PRIMARY KEY,
  cust        char(4)       NOT NULL REFERENCES customers(code),  -- どの得意先か
  issued_on   date          NOT NULL,
  amount      numeric(12,0) NOT NULL,
  paid_on     date                         -- 入金日。未入金なら空欄
);

REFERENCES customers(code) の部分が外部キー(フォーリンキー)です。「この列には、得意先テーブルの code 列に実在する値しか入れてはいけない」という約束を表します。存在しない得意先コード「C999」で請求書を作ろうとすると、PostgreSQLは拒否します。

customers(得意先) codenamepref C001あおば商事東京都 C002ひばり印刷神奈川県 C003みどり設計千葉県 ↑ 主キー:重複なし・空欄なし invoices(請求書) idcustamount 1C001120,000 2C00245,000 3C00198,000 4C999拒否される ↑ 外部キー:得意先に実在する値だけ
図4-1 主キーと外部キー。請求書の cust 列は、得意先の code 列を「指して」います。存在しないコード(C999)は入れられません。この「指す」関係が、リレーショナル(関係づける)という名前の由来です。

NULL:「空欄」をどう扱うか

請求書テーブルの paid_on(入金日)は、未入金の請求書では値がありません。このように「値がない」状態を、データベースではNULL(ヌル)と呼びます。

NULLは「0」でも「空文字」でもありません。「まだ分からない」「該当しない」という意味の特別な印です。この違いが実務で効いてきます。

  • 入金額が「0円」なら、0円の入金があったことになります。
  • 入金額が「NULL」なら、入金がまだ記録されていないことになります。

列の定義に NOT NULL とついていれば「この列は空欄禁止」、ついていなければ「空欄でもよい」という意味です。先ほどの定義で、会社名は NOT NULL、都道府県はそうでないのは、「社名が分からない得意先はあり得ないが、都道府県が未入力のことはある」という業務上の判断を表しています。

テーブルの定義は「業務のルール」そのもの

何を必須にするか、何を主キーにするか、どの表とどの表をつなぐか。これらはシステム部門だけで決められるものではなく、業務を知っている人の判断が必要です。テーブルの定義を読めるようになると、システム部門との会話が格段にしやすくなります。

この章のまとめ

  1. テーブルは「列の名前・データ型・決まりごと」を先に定義し、約束に合わない値を受け付けない。金額は numeric 型を使う。
  2. 主キーは行を一意に見分ける列。重複と空欄が禁止される。
  3. 外部キーは別のテーブルの主キーを「指す」列で、存在しない値を拒否する。これがテーブル同士をつなぐ糸。
  4. NULLは「値がない」ことを表す特別な印で、0とも空文字とも違う。

確認クイズ

Q1金額の列に使うべきデータ型はどれですか。

Q2主キー(PRIMARY KEY)に自動的につく約束はどれですか。

Q3入金日の列が NULL になっている請求書は、どういう状態ですか。