データ項目定義書とは

データ項目定義書は、システム全体で使用するコード値(区分値)・マスタデータの内容・初期投入データ・データ移行方針・データ量見積を定義した設計書です。テーブル定義書がテーブル構造を定義するのに対し、データ項目定義書は「何が入るか」を定義します。

① コード値・区分値の定義

システム内で使用するコード値(ステータスコード・区分値・フラグ値)を一覧で定義します。コード値の定義が設計書にない場合、実装担当者が独自判断でコードを決定してしまい、画面・バッチ・API間で不整合が生じます。

💡 コード値の管理方法

コード値の管理方法には「コードテーブル管理(DBテーブル)」と「定数管理(コード定義ファイル)」の2通りがあります。追加・変更が頻繁に起きるコードはコードテーブルで管理し、追加が稀で型安全に扱いたいコードは定数(Enumなど)で管理するのが一般的です。設計段階でどちらを採用するか方針を決定します。

コード種別コード値表示名説明管理方法
受注ステータス
(order_status)
10受注入力中受注入力フォームで作業中の状態コードテーブル
(c_order_status)
20受注確定受注承認済みで処理待ちの状態
30出荷済み倉庫から出荷完了した状態
90キャンセル受注取り消し済みの状態
税区分
(tax_type)
10標準税率(10%)一般的な商品に適用定数
(Enum定義)
8軽減税率(8%)食料品・新聞等に適用
0非課税医療・教育等に適用
支払方法
(payment_method)
1クレジットカードコードテーブル
(c_payment_method)
2銀行振込

② 初期マスタデータの定義

システム稼働開始時にDBに投入が必要な初期データ(種別マスタ・地域マスタ・設定マスタなど)を定義します。データ量が多い場合はCSVファイルとして管理します。

テーブル名初期データ件数データ取得方法投入タイミング備考
c_order_status(受注ステータス)4件本設計書に全件記載初回リリース時
m_category(商品カテゴリ)約50件業務担当者提供CSVから投入初回リリース時初期カテゴリ一覧は業務担当者が作成
m_prefecture(都道府県)47件本設計書にSQL添付初回リリース時変更なし・定常固定データ
m_user(初期ユーザー)約5件システム管理者が登録初回リリース後・手動登録パスワードは初期値設定→初回ログイン時変更強制

③ データ移行方針の定義

既存システムからの移行対象データと移行方針を定義します。データ移行の範囲・変換ロジック・移行タイミングを基本設計段階で確定させます。

移行対象現行テーブル新テーブル移行件数(概算)変換ロジック移行タイミング
顧客マスタTBL_CUSTOMERm_customer約1万件文字コードShift-JIS→UTF-8変換。電話番号ハイフン統一化本番移行日の前日夜間
商品マスタM_PRODUCTm_product約3,000件税区分コードの変換(旧コード→新コード)本番移行日の前日夜間
受注データTBL_ORDERt_order / t_order_detail過去3年分(約30万件)ヘッダ・明細の分割。旧ステータス→新ステータスコード変換本番移行日の前日夜間
画像ファイルファイルサーバー /data/img新ファイルサーバー / S3約5GBファイル名変換(商品コード変換に伴うリネーム)本番移行日の前日夜間

⚠️ 移行対象外データの明示も必要

「何を移行するか」だけでなく「何を移行しないか」も明示することが重要です。例:「5年以上前の受注データは移行対象外とし、必要な場合は旧システムで参照する」のような方針を明示することで、移行範囲の認識齟齬を防ぎます。

④ データ量見積(初期・最大・増加率)

DBの容量設計・パーティション設計・アーカイブ設計の根拠として、テーブル別のデータ量見積を行います。

テーブル初期件数年間増加率5年後推定件数推定サイズ(5年後)備考
m_customer10,000件10%/年約16,100件約3MB
m_product3,000件5%/年約3,800件約2MB
t_order300,000件(移行分)100,000件/年約800,000件約400MB3年経過後にアーカイブ検討
t_order_detail900,000件(移行分)300,000件/年約2,400,000件約1.2GBt_orderに連動してアーカイブ
l_operation_log0件(新規)500,000件/年約2,500,000件約2GB1年経過後にパーティション設計

⑤ データ保持期間・アーカイブ方針

法令要件・業務要件に基づいてデータ保持期間とアーカイブ方針を定義します。

テーブル保持期間法令根拠(例)アーカイブ方法
t_order(受注データ)7年間法人税法・消費税法(帳簿書類の保存義務)3年経過後に別テーブル(t_order_archive)へ移動
l_operation_log(操作ログ)3年間社内セキュリティポリシー1年経過後にCSV形式でファイルサーバーへ退避・DB削除
m_customer(顧客データ)退会後3年個人情報保護法(個人情報の利用目的の範囲)退会フラグ更新→3年後に匿名化処理

Python Tips — マスタCSVをバリデーションしてDB投入する

業務担当者から提供されるマスタデータCSVをバリデーションしてDB投入するスクリプトは、移行作業・初期データ投入で非常に有用です。

Python — マスタCSVバリデーション&DB投入
"""
業務担当者提供のマスタCSVをバリデーションしてPostgreSQLに投入するスクリプト。
pip install pandas psycopg2-binary
"""
import pandas as pd
import psycopg2
from psycopg2.extras import execute_values
from dataclasses import dataclass
from typing import Optional
import re


@dataclass
class ValidationError:
    row: int
    column: str
    message: str


def validate_category_csv(df: pd.DataFrame) -> list[ValidationError]:
    """商品カテゴリCSVのバリデーション"""
    errors = []
    required_cols = ["category_code", "category_name", "parent_code", "sort_order"]

    # 必須カラム存在チェック
    for col in required_cols:
        if col not in df.columns:
            errors.append(ValidationError(0, col, f"必須カラム '{col}' が見つかりません"))
    if errors:
        return errors

    for idx, row in df.iterrows():
        row_num = idx + 2  # ヘッダー行を含めて人間が読む行番号

        # category_code: 必須・英数字アンダースコアのみ
        code = str(row.get("category_code", "")).strip()
        if not code:
            errors.append(ValidationError(row_num, "category_code", "カテゴリコードは必須です"))
        elif not re.match(r'^[A-Za-z0-9_]+$', code):
            errors.append(ValidationError(row_num, "category_code", "半角英数字とアンダースコアのみ使用可"))

        # category_name: 必須・50文字以内
        name = str(row.get("category_name", "")).strip()
        if not name:
            errors.append(ValidationError(row_num, "category_name", "カテゴリ名は必須です"))
        elif len(name) > 50:
            errors.append(ValidationError(row_num, "category_name", f"50文字以内(現在{len(name)}文字)"))

        # sort_order: 数値
        try:
            int(row.get("sort_order", 0))
        except (ValueError, TypeError):
            errors.append(ValidationError(row_num, "sort_order", "表示順は整数で入力してください"))

    # category_code の重複チェック
    dup = df["category_code"].dropna().astype(str).str.strip()
    dup_values = dup[dup.duplicated()].tolist()
    if dup_values:
        errors.append(ValidationError(0, "category_code", f"重複コードあり: {dup_values}"))

    return errors


def insert_categories(conn, df: pd.DataFrame) -> int:
    """バリデーション済みのカテゴリCSVをDBに投入"""
    records = [
        (
            str(row["category_code"]).strip(),
            str(row["category_name"]).strip(),
            str(row["parent_code"]).strip() if pd.notna(row["parent_code"]) else None,
            int(row["sort_order"]),
        )
        for _, row in df.iterrows()
    ]
    sql = """
        INSERT INTO m_category (category_code, category_name, parent_code, sort_order)
        VALUES %s
        ON CONFLICT (category_code) DO UPDATE SET
            category_name = EXCLUDED.category_name,
            sort_order = EXCLUDED.sort_order;
    """
    with conn.cursor() as cur:
        execute_values(cur, sql, records)
    conn.commit()
    return len(records)


if __name__ == "__main__":
    CSV_FILE = "category_master.csv"
    DB_CONFIG = {"host":"localhost","port":5432,"dbname":"mydb","user":"myuser","password":"mypassword"}

    df = pd.read_csv(CSV_FILE, encoding="utf-8-sig", dtype=str)
    print(f"読込件数: {len(df)}件")

    errors = validate_category_csv(df)
    if errors:
        print(f"\n❌ バリデーションエラー {len(errors)}件:")
        for e in errors:
            print(f"  行{e.row} [{e.column}] {e.message}")
    else:
        conn = psycopg2.connect(**DB_CONFIG)
        count = insert_categories(conn, df)
        conn.close()
        print(f"\n✅ {count}件を投入しました")

定義チェックリスト

チェック項目確認ポイント
□ 全コード値・区分値が定義されているかシステム内で使用する全フラグ・ステータス・区分コードが一覧化されているか
□ コード値の管理方法が決定されているかコードテーブル管理か定数管理かが決まっているか
□ 初期マスタデータが定義されているか初回リリース時に投入すべき全マスタデータが準備されているか
□ データ移行方針が定義されているか移行対象・変換ロジック・移行タイミング・移行対象外データが定義されているか
□ データ量見積が完了しているか初期件数・増加率・5年後推定件数・サイズ見積が全主要テーブルに定義されているか
□ データ保持期間・アーカイブ方針が定義されているか法令要件・業務要件に基づいた保持期間と削除/アーカイブ方法が定義されているか