金曜の夕方に、同じ行を同じ順番で動かしていた
シートの「状態」列が発送済みになった行を選び、コピーして別シートへ貼り、元の行を消します。私は、この作業を毎週金曜の夕方にやっておりました。
10分もかからない作業です。ところが、行を消す直前に手が止まる回数だけは、毎回ありました。貼り付け先を間違えていないか、選択範囲が1行ずれていないか——小さな不安が、10分を倍の長さに感じさせるのです。
この作業を Apps Script に置き換えようと決めたとき、最初にやったのは「自動化して」とだけ Antigravity に頼むことでした。
最初の依頼は、曖昧すぎました
返ってきたコードは動きました。ただし、移した行をそのまま消す作りで、元のデータを残す仕組みも、試しに動かす手段もありませんでした。
私の依頼が「何を」「どの列で」「失敗したらどうするか」を何も言っていなかったのですから、当然の結果です。コードの出来というより、頼み方の問題でした。
消す処理は、必ず「試しに動かす」と「元を残す」を先に置く。 非エンジニアが最初の自動化で守るのは、この一文だけで足りると私は考えています。
依頼文に入れる4つのこと
私が見直したのは、コードではなく依頼の側でした。Antigravity は、書いてあることには丁寧に応えてくれますが、書いていない前提までは補ってくれません。シートの名前、列の並び、「どうなったら完了か」——頭の中では当たり前のことほど、文字にして渡す必要がありました。
次の4点を書くだけで、返ってくるコードはずいぶん安全になります。
| 入れること | 書き方の例 |
|---|---|
| シート名と列名 | 「注文」シートの1行目が見出し。列は 日付・品目・数量・単価・状態 |
| 動かす条件 | 「状態」列が 発送済 の行だけ |
| 動かし先 | 「完了」シートの最終行の下に追記する |
| 安全装置 | 最初は移すだけで消さない。試走用のスイッチを付ける |
依頼文は、たとえば次のようになります。
Google スプレッドシート用の Apps Script を1つ書いてください。
- 「注文」シートの1行目は見出しで、列は 日付・品目・数量・単価・状態 です
- 「状態」が「発送済」の行を「完了」シートの末尾へ追記します
- 追記が終わった行だけを「注文」から削除します
- 先頭に DRY_RUN という変数を置き、true の間は何も書き換えず、
移す予定の行数だけをログに出してください
- シート名や見出しが見つからないときは、理由が分かる文言でエラーにしてください「コメントは日本語で」と添えておくと、あとで読み返すときに助かります。
返ってきたコードを、読める範囲で確かめる
私が最終的に使っている形は、次のとおりです。長く見えますが、やっていることは「探す、移す、消す」の3つだけです。
// true の間は何も書き換えず、移す予定の行数をログに出すだけ
const DRY_RUN = true;
function archiveShipped() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const src = ss.getSheetByName('注文');
const dst = ss.getSheetByName('完了');
if (!src || !dst) {
throw new Error('シートが見つかりません。「注文」と「完了」の名前を確認してください');
}
const values = src.getDataRange().getValues();
const statusCol = values[0].indexOf('状態');
if (statusCol === -1) {
throw new Error('1行目に「状態」の見出しがありません');
}
// 1行目(見出し)は除き、発送済の行だけを集める
const moving = values.slice(1).filter(row => row[statusCol] === '発送済');
Logger.log('移す予定: ' + moving.length + ' 行(DRY_RUN=' + DRY_RUN + ')');
if (moving.length === 0 || DRY_RUN) return;
// 先に追記し、成功してから削除する
dst.getRange(dst.getLastRow() + 1, 1, moving.length, values[0].length)
.setValues(moving);
// 行番号がずれないよう、下から順に削除する
for (let i = values.length - 1; i >= 1; i--) {
if (values[i][statusCol] === '発送済') src.deleteRow(i + 1);
}
}読むときの目印は3つです。
DRY_RUNが true なら、書き換えの手前で必ず終わる- 追記(
setValues)が先、削除(deleteRow)が後 - 削除は下からです。上から消すと、次の行が1つずつ上にずれて取りこぼしてしまいます
コードの全部を理解する必要はありません。この3点が入っているかどうかを確認し、入っていなければ Antigravity に「DRY_RUN と、下からの削除を入れてください」と頼み直せば済みます。
シートに貼って、試走して、本番にする
手順は短く切ります。
- 対象のスプレッドシートを開き、メニューの「拡張機能」から「Apps Script」を選びます。
- 開いたエディタの
コード.gsの中身を消し、上のコードを貼り付けて保存します。 - 関数の選択欄で
archiveShippedを選び、「実行」を押します。 - 初回は「承認が必要です」と表示されます。画面の案内に沿って、自分のアカウントで許可します。
- 下の実行ログに「移す予定: N 行」と出れば試走は成功です。シートの中身は変わっていません。
N が想像した件数と合うことを目で確かめてから、DRY_RUN を false に変えて、もう一度実行します。
本番の前には、スプレッドシート全体を「コピーを作成」で複製しておくのが安心です。ひと手間ですが、肩の荷が下りる感覚は大きく違います。
毎週自動で動かす(トリガー)
エディタ左のメニューにある時計のアイコン「トリガー」から、「トリガーを追加」を選びます。
実行する関数に archiveShipped、イベントのソースに「時間主導型」、種類に「週ベースのタイマー」を選び、曜日と時間帯を決めて保存します。
私は金曜の夕方ではなく、あえて土曜の早朝にしました。人が編集している最中にスクリプトが走ると、状態を書き換える途中の行を見てしまうことがあるためです。
つまずきやすい所の見分け方
| 症状 | まず疑うこと |
|---|---|
| 「シートが見つかりません」と出る | シート名の前後の空白、全角と半角の違い |
| 件数が 0 のまま | 「状態」列の値に空白が混じっている(`'発送済 '` など) |
| 承認の画面が何度も出る | 複数のアカウントでログインしていて、別のアカウントが選ばれている |
| トリガーが動いた形跡がない | 左メニュー「実行数」で、失敗の理由が記録されていないか |
件数が 0 のままの場合は、比較の前に値を整える手もあります。String(row[statusCol]).trim() === '発送済' のように書き換えれば、見た目では分からない空白の違いを吸収できます。これも Antigravity に「空白を無視して比較してください」と頼めば足ります。
次にやること
まずは、いま一番「手が止まる」手作業を1つだけ選んでください。そして、上の4点を入れた依頼文を、消さない形で書いてみていただければと思います。
動いたら、それを来週の自分に任せます。私はその分の10分で、シートの外の仕事に戻るようにしております。