本番共有スプレッドシートを壊さず一括更新する型(GAS)
複数人が使っている本番シートに対し、AIが担当者名の一括置換や誤登録行の削除を安全に行うための設計。dryRun→照合キー付き適用→独立read-backの3段と、GASのコード雛形・実際に踏んだ落とし穴つき。
約3.3万トークンの節約 (API料金換算で約50円分)。 要件定義・技術調査・試行錯誤ぶんのトークンがまるごと不要になります。※ 出品者申告とレビューに基づく推定値。モデル・タスク内容により変動します。
この巻物について
「本番共有スプレッドシートを壊さず一括更新する型(GAS)」は、Google WorkspaceカテゴリのAI指示書(MDファイル)です。複数人が使っている本番シートに対し、AIが担当者名の一括置換や誤登録行の削除を安全に行うための設計。dryRun→照合キー付き適用→独立read-backの3段と、GASのコード雛形・実際に踏んだ落とし穴つき。この巻物をAIに読み込ませると、ゼロから設計・調査する場合に比べて 約3.3万トークン(API料金換算で約50円)・73%のトークンを節約できます。
- カテゴリ
- Google Workspace
- 対応AI
- claude-code、cursor、codex-cli
- ライセンス
- 商用利用可 (再販不可)
- 価格
- 無料
- ゼロから開発時
- 約4.5万トークン
- この巻物使用時
- 約1.2万トークン
- 節約量
- 約3.3万トークン (約50円)
- 更新日
- 2026-08-19
使い方 (AIに渡す3つの方法)
いちばん簡単なのはワンライナー。Claude Code のターミナルに貼るだけです。
claude "https://makimono-md.vercel.app/api/v1/files/gas/raw を読み込んで、この指示書どおりに実装して"
中身
他人が使っている本番スプレッドシートを壊さずに一括更新する(GAS)
複数人が日常業務で使っている共有スプレッドシートに対して、AI エージェントが 「担当者名を一括置換する」「誤登録した行を消す」といった破壊的な変更を安全に行うための型。
対象: Google Apps Script(clasp 管理 / Drive コマンドキュー方式など、AI から関数を呼べる構成)。
前提知識: dryRun と read-back verify を必ずセットで設計すること。
1. 設計原則(これを外すと事故る)
| 原則 | 理由 |
|---|---|
| 変更はホワイトリスト登録した専用関数にする | 汎用の「任意セルに書く」コマンドを AI に持たせない。事故の上限を関数の仕様で縛る |
opts.dryRun を用意し、先に必ず dryRun で対象一覧を出す | 何件・どの行が変わるかを人間が読める形で確認してから適用する |
| 期待値の照合キーを引数で必須にする | 「この行は本当に消していい行か」を関数側で検証する。行番号だけを信じない |
| 件数上限を関数内に持つ(例 50件) | ロジックのバグで全行書き換えるのを物理的に防ぐ |
| 行削除は降順で行う | 昇順だと削除のたびに行番号がずれる |
書き込み後 SpreadsheetApp.flush() → 同じ関数内で読み直して照合 | setValue は保護範囲・データ検証・結合セルで silent ignore されることがある |
| 別コマンドでもう一度読み直す(独立 read-back) | 関数の戻り値だけを信じない。呼び出し側から見た最終状態を確認する |
| 隣接列・隣接行に触れないことを明示して検証する | 「担当A列だけ変えるつもりが担当B列も変えた」を防ぐ |
2. 一括置換コマンドの雛形
/**
* 指定シートの1行分(横並びのブロック構造)を走査し、対象セルだけを置換する。
* @param {string[]} oldValues 置換対象の値(表記ゆれは正規化して比較)
* @param {string} newValue 新しい値
* @param {{dryRun:boolean}} opts
*/
function admin_replaceInRow(oldValues, newValue, opts) {
if (!Array.isArray(oldValues) || oldValues.length === 0) throw new Error('oldValues が空です');
const replacement = String(newValue || '').trim();
if (!replacement) throw new Error('newValue は必須です');
const dryRun = Boolean(opts && opts.dryRun === true);
const TARGET_ROW = 8; // 書き換える行
const FIRST_COL = 13; // ブロック開始列
const BLOCK_WIDTH = 3; // ブロックの列数(1列目だけを対象にする)
const LABEL_ROW = 2; // 空ブロック判定に使う行
const MAX_CHANGES = 50;
// 全角/半角スペースを除去して比較する(「山田 太郎」と「山田太郎」を同一視)
const norm = function (v) { return String(v || '').replace(/[\s ]+/g, ''); };
const targets = {};
oldValues.forEach(function (v) { targets[norm(v)] = true; });
const sheet = SpreadsheetApp.openById('<スプレッドシートID>').getSheetByName('<シート名>');
if (!sheet) throw new Error('シートが見つかりません');
const lastCol = sheet.getLastColumn();
const width = Math.max(0, lastCol - FIRST_COL + 1);
const labels = sheet.getRange(LABEL_ROW, FIRST_COL, 1, width).getValues()[0];
const values = sheet.getRange(TARGET_ROW, FIRST_COL, 1, width).getValues()[0];
const changes = [];
for (let col = FIRST_COL; col + BLOCK_WIDTH - 1 <= lastCol; col += BLOCK_WIDTH) {
const idx = col - FIRST_COL;
if (!String(labels[idx] || '').trim()) continue; // 未使用ブロックは飛ばす
const before = String(values[idx] || '');
// 「担当:山田太郎」のようなプレフィックスは保持したまま氏名部分だけ差し替える
const m = before.match(/^(<プレフィックス>[::])/);
const prefix = m ? m[1] : '';
if (!targets[norm(prefix ? before.slice(prefix.length) : before)]) continue;
changes.push({ col: col, before: before, after: prefix + replacement });
}
if (changes.length > MAX_CHANGES) throw new Error('上限超過: ' + changes.length);
const failed = [];
if (!dryRun && changes.length) {
changes.forEach(function (c) { sheet.getRange(TARGET_ROW, c.col).setValue(c.after); });
SpreadsheetApp.flush();
const after = sheet.getRange(TARGET_ROW, FIRST_COL, 1, width).getValues()[0];
changes.forEach(function (c) {
const actual = String(after[c.col - FIRST_COL] || '');
if (actual !== c.after) failed.push({ col: c.col, expected: c.after, actual: actual });
});
}
return { ok: true, dryRun: dryRun, changes: changes, failed: failed };
}
呼び出し順:
admin_replaceInRow([...], '<新しい値>', {dryRun: true})→changesを人間が確認- 同じ引数で
{dryRun: false} - 別コマンドで対象行を読み直し、旧値が 0 件になったことを確認する
3. 誤登録行を消すコマンドの雛形(照合ガード付き)
行番号だけで消さない。「消していい行の目印」を引数で受け取り、一致した行だけ消す。
function admin_deleteRows(rowNums, expectPrefix) {
if (!Array.isArray(rowNums) || rowNums.length > 5) throw new Error('一度に消せるのは5行までです');
const prefix = String(expectPrefix || '').trim();
if (!prefix) throw new Error('expectPrefix は必須です');
const sheet = SpreadsheetApp.openById('<スプレッドシートID>').getSheetByName('<シート名>');
const deleted = [], skipped = [];
rowNums.map(Number).sort(function (a, b) { return b - a; }) // 降順で削除
.forEach(function (row) {
const key = String(sheet.getRange(row, 1).getDisplayValue() || '');
if (key.indexOf(prefix) !== 0) { skipped.push({ row: row, key: key, reason: '照合キー不一致' }); return; }
sheet.deleteRow(row);
deleted.push({ row: row, key: key });
});
return { ok: true, deleted: deleted, skipped: skipped, lastRowAfter: sheet.getLastRow() };
}
4. 実際に踏んだ落とし穴
- タイムスタンプ列は文字列で照合できない。
getValue()はDateを返すので、 JSON で見た2026-08-18T11:18:16.825Zを照合キーにすると必ず不一致になる。getDisplayValue()を使い、シート表示どおりの形式(例2026/08/18 20:18:17)で照合する。 ※ガードが効いて「削除0件・スキップ2件」で返ってきたのは正しい挙動。ここで安易にガードを外さない。 - 人名・ラベルの表記ゆれ。
山田 太郎と山田太郎、全角コロンと半角コロンが混在する。 比較時だけ正規化し、書き戻すときは元のプレフィックスを保持する。 - 長時間ジョブは結果が返らない。AI から関数を実行する仕組み(コマンドキュー等)では 実行環境の時間上限(GAS は6分)に当たると結果ファイルが書かれず「無応答」に見える。 重い生成処理と一括更新を同じ実行に載せない。
- 同じ作業ツリー・同じキューを別の作業者/エージェントが使っていることがある。 結果ファイルが自分のものか、コマンド名で必ず突き合わせる。
5. 完了報告の基準
次の3つが揃うまで「完了」と言わない。
- dryRun の対象一覧と、実行後の
changes件数が一致している failedが空- 別コマンドで読み直した最新状態に、変更前の値が残っていない(件数で示す)
よくある質問
+「本番共有スプレッドシートを壊さず一括更新する型(GAS)」とは何ですか?
複数人が使っている本番シートに対し、AIが担当者名の一括置換や誤登録行の削除を安全に行うための設計。dryRun→照合キー付き適用→独立read-backの3段と、GASのコード雛形・実際に踏んだ落とし穴つき。
+どれくらいトークン(費用)を節約できますか?
ゼロから開発すると約4.5万トークンかかりますが、この巻物を使えば約1.2万トークンで済みます。差し引き約3.3万トークン(API料金換算で約50円)・73%の節約です。
+どうやって使いますか?
無料です。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 既定・適用前バックアップ・触っていないセルの数式不変検査で安全に書き換える設計手順。列ごとの数式復元と、テストが緑のまま壊れる典型例つき。
この巻物、誰かのトークンも救えます
𝕏 で節約レシートをシェア