本番スプレッドシートに「新しいレコードの列ブロック」を安全に増やす型(GAS)
横並び1レコード=N列のシートに、既存ブロックの複製で新しい列ブロックを自動追加する型。数式の相対参照追従・IMPORTRANGEの絶対URL差し替え・日付セルのread-back照合の罠・本番検証用の撤去コマンドまで。
約5.3万トークンの節約 (API料金換算で約80円分)。 要件定義・技術調査・試行錯誤ぶんのトークンがまるごと不要になります。※ 出品者申告とレビューに基づく推定値。モデル・タスク内容により変動します。
この巻物について
「本番スプレッドシートに「新しいレコードの列ブロック」を安全に増やす型(GAS)」は、Google WorkspaceカテゴリのAI指示書(MDファイル)です。横並び1レコード=N列のシートに、既存ブロックの複製で新しい列ブロックを自動追加する型。数式の相対参照追従・IMPORTRANGEの絶対URL差し替え・日付セルのread-back照合の罠・本番検証用の撤去コマンドまで。この巻物をAIに読み込ませると、ゼロから設計・調査する場合に比べて 約5.3万トークン(API料金換算で約80円)・85%のトークンを節約できます。
- カテゴリ
- Google Workspace
- 対応AI
- claude-code、cursor、codex-cli
- ライセンス
- 商用利用可 (再販不可)
- 価格
- 無料
- ゼロから開発時
- 約6.2万トークン
- この巻物使用時
- 約9,000トークン
- 節約量
- 約5.3万トークン (約80円)
- 更新日
- 2026-09-01
使い方 (AIに渡す3つの方法)
いちばん簡単なのはワンライナー。Claude Code のターミナルに貼るだけです。
claude "https://makimono-md.vercel.app/api/v1/files/gas-5/raw を読み込んで、この指示書どおりに実装して"
中身
本番スプレッドシートに「新しいレコードの列ブロック」を安全に増やす型(GAS)
横並び(wide format)で 1 レコード = N 列のブロックが並ぶ運用シートに、新しいレコードのブロックを プログラムから追加するための型。現場が毎日使っている本番シートに、人の手コピペを廃止して 「フォームに入力 → ブロックが自動でできる」を実現する。
対象: Google Apps Script(clasp 管理 / AI から関数を呼べる構成)。 似た型に「既存セルを一括更新する」ものがあるが、本書は列を増やす側の落とし穴に絞る。
0. まず実測する(推測でレイアウトを決めない)
wide format のシートは「何行目が何か」がドキュメント化されていないことが多い。 書き込みコードを1行も書く前に、読み取り専用のプローブ関数で実形状を取る。
/** 指定ブロックの実形状を返す(読み取り専用) */
function debug_blockShape(blockStart) {
const sheet = SpreadsheetApp.openById('<スプレッドシートID>').getSheetByName('<シート名>');
const lastCol = sheet.getLastColumn();
const blocks = [];
for (let bs = FIRST_COL; bs + (BLOCK_WIDTH - 1) <= lastCol; bs += BLOCK_WIDTH) blocks.push(bs);
const target = Number(blockStart) || blocks[blocks.length - 1];
return {
lastCol: lastCol, maxCols: sheet.getMaxColumns(),
blockCount: blocks.length, blockStarts: blocks, target: target,
// 見出し行の値と数式を両方返す(値だけ見ると数式の存在に気付けない)
headValues: sheet.getRange(1, target, HEAD_ROWS, BLOCK_WIDTH).getValues(),
headFormulas: sheet.getRange(1, target, HEAD_ROWS, BLOCK_WIDTH).getFormulas(),
// ドロップダウンの有無(コピーで運ばれるか判断するため)
validation: String((sheet.getRange(20, target + BLOCK_WIDTH - 1).getDataValidation() || {}).getCriteriaType
? sheet.getRange(20, target + BLOCK_WIDTH - 1).getDataValidation().getCriteriaType() : ''),
columnWidths: [0, 1, 2].map(function (i) { return sheet.getColumnWidth(target + i); }),
frozenRows: sheet.getFrozenRows(), frozenCols: sheet.getFrozenColumns()
};
}
実測でよく判明すること(どれも推測だと外す):
- 本体データが終わる行と、その下に集計対象外の旧行が残っている(
getLastRow()を信じると件数が倍になる) - 見出しに見えるセルが実は数式(
COUNTIF/IMPORTRANGE) - ブロック先頭列が「N 列おき」の規則から外れている列がある
- URL セルが
HYPERLINK数式ではなく素の文字列
1. 新ブロックは「既存ブロックの複製」で作る(自前で組み立てない)
sheet.getRange(1, templateStart, COPY_ROWS, BLOCK_WIDTH)
.copyTo(sheet.getRange(1, newStart, COPY_ROWS, BLOCK_WIDTH),
SpreadsheetApp.CopyPasteType.PASTE_NORMAL, false);
PASTE_NORMAL は 書式・数式・データ検証(プルダウン)・条件付き書式をまとめて運ぶ。
自前で setFormula を書き直すと、表記ゆれ(全角/半角、集計範囲の行数違い)で既存ブロックと
微妙に違う式ができ、集計だけが静かにズレる。
複製したあとに消すもの・直すもの:
| 対象 | 処理 | 理由 |
|---|---|---|
| データ行 | clearContent() | 検証と書式は残す(clear() だとプルダウンごと消える) |
| 見出し行 | clearContent() → 新しい値を setValues | |
相対参照の集計式(=COUNTIF(X15:X234,"済")) | 触らない | コピーで新しい列へ自動追従する |
絶対URLを持つ数式(IMPORTRANGE("https://…")) | URL を差し替える。無ければ clearContent() | コピー元のレコードを指したまま残る=他レコードのデータが混ざる |
| 列幅 | setColumnWidth() で別途コピー | copyTo は列幅を運ばない |
// IMPORTRANGE の URL だけを差し替える純粋関数(テスト可能)
function rewriteImportrange(formula, newUrl) {
if (!newUrl) return ''; // 空 = クリア指示
return String(formula || '').replace(
/(IMPORTRANGE\s*\(\s*)(["'])([^"']*)(\2)/i,
function (_, prefix, quote, oldUrl, close) { return prefix + quote + newUrl + close; });
}
2. 列を増やす方向のガード(これが無いと全レコードがズレる)
const newStart = lastBlockStart + BLOCK_WIDTH;
if ((newStart - FIRST_COL) % BLOCK_WIDTH !== 0) throw new Error('ブロック位置が不正: ' + newStart);
if (sheet.getMaxColumns() < newStart + BLOCK_WIDTH - 1) {
sheet.insertColumnsAfter(sheet.getMaxColumns(), BLOCK_WIDTH); // 追加は右端だけ
}
- 追加は右端のみ。中間への
insertColumnsは右側の全ブロックの列番号を変え、 他システムが保存している「レコード → 列番号」の対応を一斉に壊す - 削除も最終ブロックのみ許可し、期待するキー(レコード名など)の一致を関数側で検証する
- 冪等性: 同じキーのブロックが既にあれば新規作成せず再利用する。 「押すたびにブロックが増える」が最悪の事故
3. 日付書式セルの read-back を文字列で照合しない(実害あり)
書き込み後の flush() → 読み直し照合は必須だが、日付の表示形式が付いたセルに
setValue('2026/12/01') すると Sheets 側が Date 値に変換して保存する。
読み戻すと Date オブジェクトなので、素朴な String(actual) !== expected は必ず不一致になる。
mismatches: [{ row: 4, expected: "2026/12/01",
actual: "Tue Dec 01 2026 00:00:00 GMT+0900" }] ← 値は正しいのに不一致
値は正しいのに毎回「不一致」が出ると、本物の書き込み失敗(保護範囲やデータ検証による silent ignore)を見逃す。照合側を日付に対応させる:
function sameCell(actual, expected) {
const norm = function (v) {
if (v instanceof Date && !isNaN(v.getTime())) {
const jst = new Date(v.getTime() + 9 * 60 * 60 * 1000); // タイムゾーンは自環境に合わせる
const pad = function (n) { return ('0' + n).slice(-2); };
return jst.getUTCFullYear() + '/' + pad(jst.getUTCMonth() + 1) + '/' + pad(jst.getUTCDate());
}
const s = String(v == null ? '' : v).trim();
const m = s.match(/^(\d{4})[/-](\d{1,2})[/-](\d{1,2})$/); // 2026/12/1 と 2026/12/01 を同一視
return m ? m[1] + '/' + ('0' + m[2]).slice(-2) + '/' + ('0' + m[3]).slice(-2) : s;
};
return norm(actual) === norm(expected);
}
日付として解釈できない値は従来どおり厳密比較する。緩めすぎると照合の意味が無くなる。
4. 本番で検証するための「撤去コマンド」を先に作る
本番シートでしか再現しない問題(数式の追従・プルダウン・条件付き書式)があるので、 本番で1件登録して検証するのが正しい。そのために撤去コマンドを先に用意する。
/** テスト登録を丸ごと撤去する。dryRun 既定 true */
function admin_removeTestRecord(recordId, opts) {
const dryRun = !(opts && opts.dryRun === false);
// ① キーが "__TEST__" で始まるレコードしか消せない(誤爆の上限を関数で縛る)
if (String(clientName).indexOf('__TEST__') !== 0) return { ok: false, reason: 'テストレコードではありません' };
// ② 最終ブロックであることを確認してから deleteColumns(blockStart, BLOCK_WIDTH)
// ③ 付随して作られたシート/行/フォルダも消す(フォルダは削除ではなく setTrashed(true))
// ④ 消したあと read-back して残骸ゼロを確認し、残っていたら ok:false で残骸を返す
}
検証の流れ:
register(payload, {dryRun:true})… 1セルも書かずに「何列目に作るか」を返すregister(payload)… 実行debug_blockShape(newBlockStart)… 見出し・数式・プルダウン・空のデータ行を実測で確認admin_removeTestRecord(id, {dryRun:true})→{dryRun:false}… 撤去debug_blockShape()… 元のブロック数・最終列に戻ったことを確認
戻り値の ok:true だけを信じない。同じデータを別コマンドで読み直すまで検証は終わっていない。
5. AI に渡すときのチェックリスト
- 読み取り専用プローブで実形状を取り、その数値を仕様書に貼ってから実装を依頼したか
- 新ブロックは既存ブロックの
copyTo(PASTE_NORMAL)で作る指示になっているか - 絶対URL入り数式(
IMPORTRANGE等)の差し替え/クリアを明記したか - 「既存ブロックには絶対に書かない」「中間への列挿入・削除は禁止」を明記したか
- キー重複時に再利用する(増殖させない)冪等性を明記したか
-
dryRunと撤去コマンドを実装と同じ依頼に含めたか - 日付セルの照合を文字列比較にしていないか
- レコード名・ラベルの生成規則が、既存の同期処理と1文字も違わないことをテストで固定したか
よくある質問
+「本番スプレッドシートに「新しいレコードの列ブロック」を安全に増やす型(GAS)」とは何ですか?
横並び1レコード=N列のシートに、既存ブロックの複製で新しい列ブロックを自動追加する型。数式の相対参照追従・IMPORTRANGEの絶対URL差し替え・日付セルのread-back照合の罠・本番検証用の撤去コマンドまで。
+どれくらいトークン(費用)を節約できますか?
ゼロから開発すると約6.2万トークンかかりますが、この巻物を使えば約9,000トークンで済みます。差し引き約5.3万トークン(API料金換算で約80円)・85%の節約です。
+どうやって使いますか?
無料です。MDファイルを Claude Code などのAIに読み込ませるだけ。ワンライナーをターミナルに貼れば実装が始まります。要件定義や技術調査を省いて実装だけにトークンを使えます。
+どのAIツールに対応していますか?
claude-code、cursor、codex-cli に対応しています。
+商用利用できますか?
ライセンスは「商用利用可 (再販不可)」です。
🤝 自分でAIを動かすのは、まだ不安…という方へ
この巻物の内容を、AIを使うプロに丸ごと任せることもできます。姉妹サービスAI代行堂なら「LINEで頼むだけで、仕事が完成」。
関連する巻物
GAS完全自動化テンプレ — Driveコマンドキュー方式
Google Apps Script の「毎回エディタで▶実行」を根絶。Drive 経由のコマンドキューで、初回1クリック以降は AI がすべての GAS 関数をリモート実行できるようになるテンプレート指示書。
人間の手入力台帳を壊さずに自動更新する — GAS Web App upsert 設計
各PC/各拠点の点検結果を、人間が手運用しているスプレッドシート台帳へ自動反映する。手入力列とコメントを絶対に壊さない突合設計、タブ/列の解決、並行POST対策、配布シークレットの落とし穴まで。
数式まみれの業務スプレッドシートを、Webアプリから壊さずに編集させる型
ArrayFormula と per-row 数式が混在する台帳を、セル単位 allowlist・dry-run 既定・適用前バックアップ・触っていないセルの数式不変検査で安全に書き換える設計手順。列ごとの数式復元と、テストが緑のまま壊れる典型例つき。
この巻物、誰かのトークンも救えます
𝕏 で節約レシートをシェア