会員登録すると
学習することができます。
会員登録する(無料)
登録済みの方はこちら
ログイン

機能追加のデータ設計 ― 既存のデータと両立させて足す

目安学習時間 20分

課題

全問正解でレクチャー完了です。

【問題1】

既存の会員の値を埋められない項目(例:生年月日の無い会員の生まれ年)を新しく必須にしたいとき、この講座が勧める方法はどれですか。

[選択肢]

【問題2】

会員がすでにいる表に、必須(NOT NULL)の列をデフォルトなしで足したときに起きることはどれですか。

[選択肢]
会員登録すると
学習することができます。
会員登録する(無料)

学ぶ目的

新しい項目を「必須」で足したくなる

会員登録で、新しく「生まれ年」を聞くことにしました。全員に入力してほしいので、データベースにも必須(NOT NULL)の列として足したくなります。

ここで困るのは、もう会員がいることです。既存の会員は生まれ年を入力していません。

いきなり必須の列を足すと、失敗する

会員が2人いる表に、必須の列をデフォルトなしで足してみます(PostgreSQL 16 で確認)。

ALTER TABLE members ADD COLUMN birth_year integer NOT NULL;
ERROR:  column "birth_year" of relation "members" contains null values

既存の2人には値が無いので、「必ず値がある」という約束を守れず、失敗します。

怖いのは、開発環境の空の表では、同じ文が成功することです。手元で通ったのに、本番に出した瞬間に失敗する。データが貯まっている本番だけで起きる、典型的な「後から困ること」です。

3段階で足す:広げる → 埋める → 締める

既存のデータと両立させるには、変更を3つに分けます。

段階 やること 英語での呼び名
広げる null を許して列を足す。古いコードも新しいコードも動く expand
埋める 既存の行に値を入れる migrate
締める 全行が埋まったのを確かめてから、必須の制約をかける contract

Rails のマイグレーションなら、こう書けます(ActiveRecord 8.1 で確認)。

add_column :members, :plan, :string            # 広げる
execute "UPDATE members SET plan = 'free' WHERE plan IS NULL"  # 埋める
change_column_null :members, :plan, false      # 締める

「プラン」のように全員分を決められる値なら、この順で最後まで進めます。

埋められない値もある

生まれ年はどうでしょう。生年月日を持っている会員なら、そこから埋められます。でも、持っていない会員の生まれ年は誰にも分かりません。

UPDATE 1                       ← 生年月日のある1人だけ埋まった
ALTER TABLE ... SET NOT NULL
ERROR:  column "birth_year" ... contains null values

この場合は「締める」に進めません。データベースでは null を許したまま、入力する画面の側で必須にする、という選択になります。

naminori の実例:登録のときだけ必須にした

naminori では2026年10月に、会員登録で生まれ年・お住まいの都道府県・いまの職種・興味・登録の目的・転職の希望時期を必ず聞くことにしました。そのとき決めたのが次のことです。

  • データベースでは null を許す。既存の会員との整合を保つため
  • 必須にするのは、登録フォームから会員を作るときだけ。招待・管理画面からの作成や、既存の会員の更新では求めない
  • 生年月日を持っている既存の会員は、生まれ年を埋めておく
  • 「既存の会員は、項目が空のままでも保存・更新できる」ことを、テストで確かめ続ける

既存の利用者に、必須を後付けしない

データベースではなく、プログラムの検証で必須にするときも同じ落とし穴があります。生まれ年を無条件に必須にすると、既存の会員が名前を変えようとしただけで保存に失敗します(手元で確認)。

無条件に必須      : 既存会員の更新 => false ["Birth year can't be blank"]
登録のときだけ必須: 既存会員の更新 => true

既存の利用者は、その項目が無い時代に登録した人です。新しい約束は、新しく入ってくるデータにだけかける。これが、機能追加のデータ設計の基本です。

このレクチャーで学ぶこと

  • 必須の列をいきなり足すと失敗する理由
  • 開発環境では通り、本番で失敗する落とし穴
  • 広げる → 埋める → 締めるの3段階
  • 埋められない値は、画面の側で必須にする(naminori の実例)

質問

まだ質問は投稿されていません。

質問投稿

ログイン後に質問の投稿ができます。