行列のデータモデル

CRUD行列はプログラム名 → テーブル名 → 操作セットという2段階のネスト構造で表現します。 Python では辞書のネストで実装します。

Python — データモデル定義
from collections import defaultdict
from dataclasses import dataclass, field
from typing import DefaultDict

# プログラム名 → テーブル名 → CRUD操作セット
# 例: matrix['URIAGE-TOROKU']['TOKUI'] = {'R'}
CrudMatrix = DefaultDict[str, DefaultDict[str, set]]

@dataclass
class CrudMatrixResult:
    """CRUD行列の全情報を保持するデータクラス"""
    # matrix[program][table] = {'C', 'R', 'U', 'D'} の部分集合
    matrix: CrudMatrix = field(
        default_factory=lambda: defaultdict(lambda: defaultdict(set))
    )
    # 全プログラム名のリスト(ソート済み)
    programs: list[str] = field(default_factory=list)
    # 全テーブル名のリスト(ソート済み)
    tables: list[str] = field(default_factory=list)

行列の構築

Python — CRUD行列の構築
def build_crud_matrix(
    scan_results: list,   # list[ProgramSqlInfo] from PART 03
    jar_path: str | None = None
) -> CrudMatrixResult:
    """
    スキャン結果からCRUD行列を構築する。
    """
    result = CrudMatrixResult()
    all_tables: set[str] = set()

    for info in scan_results:
        prog = info.program_id

        for sql in info.sql_list:
            entries = classify_crud(sql, jar_path=jar_path)
            for entry in entries:
                table = entry.table_name.upper()
                result.matrix[prog][table].update(entry.operations)
                all_tables.add(table)

    # 一般的なシステムテーブル・ビュー名を除外するフィルタ(任意)
    EXCLUDE_TABLES = {'DUAL', 'SYSIBM_SYSDUMMY1'}
    all_tables -= EXCLUDE_TABLES

    result.programs = sorted(result.matrix.keys())
    result.tables = sorted(all_tables)

    return result

操作セットの正規化と表示形式

Python — 表示形式への変換
def ops_to_str(ops: set) -> str:
    """
    操作セットを CRUD 順の文字列に変換する。
    例: {'R', 'C'} → 'CR'
        {'D', 'U', 'R', 'C'} → 'CRUD'
        set() → ''
    """
    order = 'CRUD'
    return ''.join(c for c in order if c in ops)

def get_cell(matrix_result: CrudMatrixResult, program: str, table: str) -> str:
    """行列の特定セルを文字列で取得する"""
    ops = matrix_result.matrix.get(program, {}).get(table, set())
    return ops_to_str(ops)

JSON形式でのエクスポート

Python — JSONエクスポート
import json

def export_to_json(result: CrudMatrixResult, output_path: str) -> None:
    """CRUD行列をJSONファイルにエクスポートする"""
    data = {
        "programs": result.programs,
        "tables": result.tables,
        "matrix": {
            prog: {
                table: ops_to_str(ops)
                for table, ops in tables.items()
            }
            for prog, tables in result.matrix.items()
        }
    }
    with open(output_path, 'w', encoding='utf-8') as f:
        json.dump(data, f, ensure_ascii=False, indent=2)
    print(f'JSON出力: {output_path}')
JSON出力例
{
  "programs": ["SHOHIN-KANRI", "TOKUI-MEISHO", "URIAGE-SHUKEI", "URIAGE-TOROKU"],
  "tables": ["MEISAI", "SHOHIN", "TOKUI", "URIAGE"],
  "matrix": {
    "URIAGE-TOROKU": {
      "TOKUI":  "R",
      "SHOHIN": "R",
      "URIAGE": "CU",
      "MEISAI": "CRD"
    },
    "URIAGE-SHUKEI": {
      "TOKUI":  "R",
      "SHOHIN": "R",
      "URIAGE": "R",
      "MEISAI": "R"
    },
    "SHOHIN-KANRI": { "SHOHIN": "CRUD" },
    "TOKUI-MEISHO": { "TOKUI":  "CRUD" }
  }
}

統計情報の生成

Python — 統計情報
def print_stats(result: CrudMatrixResult) -> None:
    """CRUD行列の統計情報を表示する"""
    print(f'プログラム数: {len(result.programs)}')
    print(f'テーブル数:   {len(result.tables)}')

    # 各テーブルに何プログラムがアクセスしているか
    print('\n--- テーブル別アクセス数 ---')
    for table in result.tables:
        count = sum(
            1 for prog in result.programs
            if table in result.matrix.get(prog, {})
        )
        print(f'  {table:30s}: {count} プログラム')

    # CRUD比率
    total_ops = {'C': 0, 'R': 0, 'U': 0, 'D': 0}
    for prog in result.programs:
        for table, ops in result.matrix[prog].items():
            for op in ops:
                if op in total_ops:
                    total_ops[op] += 1
    total = sum(total_ops.values()) or 1
    print(f'\n--- 操作種別比率 ---')
    for op, cnt in total_ops.items():
        print(f'  {op}: {cnt:4d} ({cnt/total*100:.1f}%)')

次の章では…

PART 06 では構築済みCRUD行列をMarkdown・Mermaid・PlantUML形式でファイルに出力するPython実装を解説します。GitHubやNotionで即レンダリングできる形式になります。

→ PART 06 — CRUD図の出力へ