Claude Media
Claude Codeでデータ移行の項目マッピング表を作る — 型変換とコード値と件数照合

Claude Codeでデータ移行の項目マッピング表を作る — 型変換とコード値と件数照合

旧システムと新システムのテーブル定義をClaude Codeに読ませ、項目の対応・型変換・コード値の変換表を作ります。移行後の件数照合SQLまで、確かめながら進める手順です。

Claude Codeでデータ移行の項目マッピング表を作る — 型変換とコード値と件数照合

旧システムから新システムへのデータ移行で最初に作る文書が、項目マッピング表です。旧テーブルのどの列が、新テーブルのどの列に、どんな変換を経て入るのかを1行ずつ書きます。

Claude Codeには、両方のテーブル定義(DDL)を読ませて、この表の下書きを作らせられます。下書きで終わらせないために、コード値の洗い出しと、移行後の件数照合SQLまで同じ流れで用意します。

マッピング表づくりでClaude Codeに任せる範囲

Claude Codeは、コードベースを読み、ファイルを編集し、コマンドを実行する開発ツールです。概要ページには、ログをパイプで渡す使い方の例があります。DDLやCSVのヘッダを渡して表を作らせる用途は、この延長にあります。

任せる範囲は、工程で分けると見通しがよくなります。

工程Claude Codeに任せるか理由
旧新の定義を突き合わせて下書きを作るClaude Codeに任せるか任せる理由読んで照合する作業で、量が多い
型の差と桁あふれの候補を挙げるClaude Codeに任せるか任せる理由定義から機械的に拾える
業務上の意味が要る変換の決定Claude Codeに任せるか人が決める理由定義に書かれていない
件数照合SQLを書いて実行するClaude Codeに任せるか任せる理由結果を読んで直す反復に向く
本番データを読むClaude Codeに任せるか任せない理由権限と情報管理の問題

業務上の意味が要る変換とは、たとえば旧システムの区分値「9」が「不明」なのか「対象外」なのか、といった判断です。定義書にもDDLにも書かれていないので、推測で埋めさせないことが要点になります。

作業前に決めておく3つの前提

DDLとコード表だけを渡す

渡す資料は、旧新のDDLと、コード表があればその一覧です。実データの入ったダンプは渡しません。マッピング表の下書きに必要なのは構造であり、顧客の氏名や金額ではないからです。

実データを読ませる必要が出るのは、コード値の実在値を洗い出すときです。そのときも、集計結果(SELECT DISTINCTの出力)だけを渡す形にできます。

実データのファイルを読ませない設定にする

ダンプやCSVを作業ディレクトリに置く場合は、Readの拒否ルールで読み取りを止められます。公式のベストプラクティスにも、.envやsecretsディレクトリに対する拒否ルールの設定例があります。

{
  "permissions": {
    "deny": [
      "Read(./dump/**)",
      "Read(./.env)"
    ]
  }
}

これは上の公式例を、移行作業向けにパスだけ読み替えた例です。注意点が1つあります。公式の権限ページによると、Readの拒否ルールは組み込みのファイルツールと、catなどClaude Codeが認識するファイル読み取りコマンドに効きます。ファイルを自分で開くPythonやNodeのスクリプトには効きません。

スクリプトまで止めたいときは、OSレベルで制限するサンドボックスを併用します。実データがある環境では、拒否ルールだけを境界にしないほうが安全です。

確認コマンドをCLAUDE.mdに書く

公式のベストプラクティスは、Claudeに合否が返ってくる確認手段を持たせることを勧めています。リポジトリにあるなら、それを実行するコマンドがCLAUDE.mdで最も役立つ1行だとも述べています。

移行作業では、その確認手段が件数照合SQLです。規約は短く置きます。

## データ移行(マッピング)
- 旧DDLは migration/old_schema.sql、新DDLは migration/new_schema.sql
- マッピング表は migration/mapping.csv に書く(列は 旧項目/旧型/新項目/新型/変換規則/状態)
- 定義から決められない変換は、推測せず「未確定」と書いて理由を添える
- 型変換で桁あふれや精度落ちが起こりうる行は「要確認」にする
- 表を直したら migration/reconcile.sql を検証用DBで実行し、出力を貼って報告する
- 本番DBへは接続しない。接続先は環境変数 STAGING_URL のみ

「推測せず未確定と書く」の1行が、この作業で最も効きます。これがないと、空欄が埋まった表のほうが完成度が高く見え、確認が漏れます。

旧新のDDLから項目マッピング表の下書きを作る

下書きの段階では、ファイルを編集させずに読ませるところから始められます。権限ページによると、プランモードは「ファイルを読み、読み取り専用のシェルコマンドで調べるが、ソースは編集しない」モードです。まず方針だけを出させ、列の構成に問題がなければ編集を許す、という順序が取れます。

migration/old_schema.sql と migration/new_schema.sql を読んで、
旧CUSTOMER_MSTから新customersへの項目マッピング表の方針を出して。
列は 旧項目 / 旧型 / 新項目 / 新型 / 変換規則 / 状態 にする。
定義から決められない行は「未確定」にして理由を書く。

マッピング表はCSVにしておくと、レビュー用にスプレッドシートで開け、後でSQLの生成元にもできます。例えば次のような形になります(以下は説明用の架空の例です)。

旧項目,旧型,新項目,新型,変換規則,状態
CUST_NO,CHAR(8),customer_id,BIGINT,先頭ゼロを除いて整数化,確定
CUST_NM,VARCHAR(40),name,VARCHAR(100),前後空白を除去,確定
SEX_CD,CHAR(1),gender,VARCHAR(8),コード値変換表を適用,要確認
BIRTH_YMD,CHAR(8),birth_date,DATE,YYYYMMDDを日付化。00000000はNULL,要確認
CREDIT_AMT,DECIMAL(11),credit_limit,"DECIMAL(12,2)",単位が円か千円か不明,未確定
DEL_FLG,CHAR(1),deleted_at,TIMESTAMP,1なら移行日時を入れる,要確認

最後の3行のように、「状態」に未確定や要確認が残る表が、正しい下書きです。全行が確定になっている下書きは、むしろ疑う対象です。

型変換で見るべき項目

下書きを受け取ったら、人が見る前にClaude Codeへ次の観点で二巡目をかけさせると、見落としが減ります。

観点例
桁あふれ例旧が VARCHAR(40)、新が VARCHAR(20)
精度落ち例旧が DECIMAL(12,2)、新が INTEGER
文字列から日付例YYYYMMDD、空文字、00000000
NULLと空文字例旧は空文字、新はNULLで統一
文字コード例旧がShift_JIS系、新がUTF-8

どれも、旧新の定義に加えて旧データの実在値を見ないと確定しません。空文字とNULLの混在は、次のような集計で件数が分かります。

SELECT
  SUM(CASE WHEN CUST_NM IS NULL THEN 1 ELSE 0 END)       AS null_cnt,
  SUM(CASE WHEN TRIM(CUST_NM) = '' THEN 1 ELSE 0 END)    AS blank_cnt,
  SUM(CASE WHEN CUST_NM <> TRIM(CUST_NM) THEN 1 ELSE 0 END) AS padded_cnt
FROM CUSTOMER_MST;

この3つの件数が分かれば、「空文字はNULLに寄せる」「前後空白は除去する」といった変換規則を、件数つきで決められます。文字コードの問題は、移行後の新側で「?」や欠けた文字として現れるため、氏名や住所の列を数十行抜き出して旧と目で見比べる確認が欠かせません。二巡目の目的は決めることではなく、人間に確認させる行を絞ることです。

コード値の変換表をデータから洗い出す

区分値の変換は、マッピング表の中でも事故になりやすい箇所です。定義書にある値と、実際に入っている値は一致しないことがあります。

そこで、旧DBの検証用コピーから実在値と件数を取り、その結果を変換表の元にします。

-- 旧DBの検証用コピーで実行する
SELECT SEX_CD, COUNT(*) AS cnt
FROM CUSTOMER_MST
GROUP BY SEX_CD
ORDER BY cnt DESC;

この出力を貼って、変換表を作らせます。

旧値,新値,件数,備考
1,male,5210,
2,female,4980,
9,unknown,37,
(空文字),unknown,12,定義書に無い値。要確認
A,,3,定義書に無い値。変換先未確定

定義書に載っていない値(空文字やA)が見つかるのは、こういう棚卸しの典型的な成果です。変換先が決まらない値は、行を消さずに残し、決定者の名前とともに「未確定」を維持します。

変換表が確定したら、移行SQLのCASE式や変換スクリプトの生成も同じ流れで任せられます。依頼文には「CSVの行をそのままCASE式にして、表に無い値はELSEでNULLにせず、移行を止める値にして」と書いておくと、想定外の値が黙って消えにくくなります。出力は次のような形になります(説明用の架空の例です)。

CASE SEX_CD
  WHEN '1' THEN 'male'
  WHEN '2' THEN 'female'
  WHEN '9' THEN 'unknown'
  WHEN ''  THEN 'unknown'
  ELSE CAST(1/0 AS VARCHAR(8))  -- 表に無い値(例: A)で意図的にエラーにする
END AS gender

「A」のように変換先が未確定の値は、CASE式に入れない運用がこの例の狙いです。決定者が値を決めるまで、移行は未確定の値で止まります。生成物は次の節の照合でも確かめます。

件数照合SQLを書いて実行させる

マッピング表ができても、データが正しく入った保証にはなりません。移行後に旧新を突き合わせる照合SQLを、マッピング表と同じ時点で用意します。

最低限そろえたいのは次の3種類です。

-- 1. 件数(論理削除を移行対象に含めるかは、表の変換規則に合わせる)
SELECT
  (SELECT COUNT(*) FROM old_customer_mst) AS old_cnt,
  (SELECT COUNT(*) FROM customers)        AS new_cnt;
 
-- 2. キーの漏れ(旧にあって新に無いもの)
SELECT o.CUST_NO
FROM old_customer_mst o
LEFT JOIN customers n ON n.customer_id = CAST(o.CUST_NO AS BIGINT)
WHERE n.customer_id IS NULL;
 
-- 3. コード値の分布(変換表どおりの件数になっているか)
SELECT gender, COUNT(*) FROM customers GROUP BY gender;

金額列と日付列があれば、合計値と日付範囲の比較も加えます。件数が合っていても、桁のずれは合計に、日付の読み違えは最小値と最大値に出ます。

-- 4. 金額の合計(旧の単位が円なら、新も円で並べて比べる)
SELECT
  (SELECT SUM(CREDIT_AMT) FROM old_customer_mst) AS old_sum,
  (SELECT SUM(credit_limit) FROM customers)      AS new_sum;
 
-- 5. 日付の最小・最大(00000000 などの番兵値は除いて比べる)
SELECT
  (SELECT MIN(BIRTH_YMD) FROM old_customer_mst WHERE BIRTH_YMD <> '00000000') AS old_min,
  (SELECT MAX(BIRTH_YMD) FROM old_customer_mst) AS old_max,
  (SELECT MIN(birth_date) FROM customers)       AS new_min,
  (SELECT MAX(birth_date) FROM customers)       AS new_max;

旧が文字列、新が日付型なので、表示形式は揃いません。見るのは年月日の並びが同じかどうかです。合計がずれたときは、まず金額列の単位がマッピング表の「未確定」のまま進んでいないかを疑います。

実行して出力を読ませる

SQLを書かせるだけでは足りません。ベストプラクティスのページは、Claudeが完了と判断する根拠に「実行したコマンドとその出力」を求めることを勧めています。

migration/reconcile.sql を検証用DBで実行して、
旧と新の件数が一致しない項目があれば原因を調べて表を直して。
最後に、実行したコマンドと出力をそのまま貼って報告して。

「全部一致しました」という報告だけでは、本当に実行したのかが分かりません。出力が貼られていれば、人が数字だけ読めば足ります。

切り分け

件数が合わないときの切り分け

  1. Q旧と新で総件数は同じか?
    答えがいいえのとき

    総件数が違うなら、キー漏れSQLで抜けた行を特定します。論理削除や重複排除を移行対象から外していないかを、マッピング表の変換規則と照らします。

    答えがはい
  2. Qコード値の分布は変換表どおりか?
    答えがいいえのとき

    分布が違うなら、変換表に無い値が新側で空欄やデフォルト値に落ちていないかを調べます。

    答えがはい

合計値や日付範囲を比べる

件数とコード値が合っていても、金額の合計や日付の最小・最大がずれることがあります。単位や丸めの扱いを、マッピング表の「未確定」の行と見比べます。

DBそのものの移行スクリプトや、マイグレーションの往復検証は別の論点です。Alembicでの往復検証の手順がそのまま参考になります。CSVを手元で集計して検算する用途には、DuckDBプラグインが使えます。また、アプリケーションコードの移行を含む大きな案件の進め方は、コードモダナイゼーションの解説にあります。

照合を人の手作業にしないための仕組み

反復を人に頼らないようにするには、Stopフックも使えます。公式のベストプラクティスによると、StopフックはClaudeがターンを終えようとするたびにスクリプトを実行し、終了コードが2なら作業に戻します。照合スクリプトの結果が不一致なら終了コード2を返す構成にすれば、一致するまでターンが終わりません。ブロックの回数には上限があるため、永久には回りません。

定型の抽出だけを機械的に回したい場合は、非対話モードのclaude -pが使えます。--output-format jsonと--json-schemaを組み合わせると、結果を決まった形のJSONで受け取れます。

cat migration/old_schema.sql | claude -p \
  "全テーブルの列名と型を一覧にして" \
  --output-format json \
  --json-schema '{"type":"object","properties":{"columns":{"type":"array","items":{"type":"string"}}},"required":["columns"]}'

この方法は、列名の抽出のような定型作業には向きます。業務判断を含む変換規則の決定には、対話で確認しながら進める形が合います。

見落としやすい落とし穴

落とし穴

全角半角と前後の空白で、キーが一致しなくなる

旧システムのキーに全角数字や末尾の空白が混じっていると、型変換後の結合キーが一致せず、キー漏れSQLで大量の「欠落」として出ます。欠落の原因が本当に漏れなのか、正規化の不足なのかを、数行を取り出して確かめてから変換規則を直します。

まとめ

マッピング表は、確定した行の数ではなく、未確定の行がどれだけ正直に残っているかで品質が決まります。Claude Codeには、下書きと照合SQLの作成、実行、出力の報告を任せ、「業務上の意味」の確定だけを人が担う分担が現実的です。

実データは読ませず、結果の出力だけで進められる設計にしておけば、同じ手順を次の移行案件にもそのまま使い回せます。

参照した一次ソース

この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。

  1. code.claude.com/docs/en/overview
  2. code.claude.com/docs/en/best-practices
  3. code.claude.com/docs/en/permissions
  4. code.claude.com/docs/en/headless
この記事を共有:XはてブLinkedIn