2026年7月13日月曜日

GASでスプレッドシートを操作する基本|セル取得・書き込みの考え方

GASが最も活躍する場所はスプレッドシート

GAS(Google Apps Script)が業務で使われる理由の多くは、スプレッドシートを自動で操作できる点にあります。
「転記」「チェック」「集計」「定型フォーマットへの書き込み」など、人がやると地味に時間を取られる作業が、GASで一気に短縮できます。

ただし、スプレッドシート操作は“壊しやすい”領域でもあります。
存在しないシート名を指定してしまう、IDを間違える、権限が足りない、想定外の値が入っている──こうした理由で簡単にエラーが出ますし、書き込みは上書きで戻せないこともあります。

そこで第2部の最初となるこの記事では、スプレッドシート操作の最も基本となる「考え方」を整理しながら、1セル取得・1セル書き込みを確実に理解していきます。
さらに、GAS010で学んだ try-catch を活かした、安全な読み取り・書き込みの実務サンプルも紹介します。

目次

SpreadsheetAppの役割(階層構造)

GASでスプレッドシートを操作するとき、必ず登場するのが SpreadsheetApp です。
SpreadsheetAppは「スプレッドシート操作の入口」であり、ここからファイル(Spreadsheet)やシート(Sheet)やセル(Range)へ降りていくイメージになります。

まずは、この階層構造を暗記する価値があるレベルで押さえてください。

  • SpreadsheetApp:スプレッドシート操作の入口
  • Spreadsheet:1つのスプレッドシートファイル
  • Sheet:ファイル内の1枚のシート
  • Range:セル、またはセル範囲(1セルもRange)

この構造が頭に入ると、コードを読んだときに「今どのレベルを触っているか」が分かり、ミスが減ります。
逆に、ここが曖昧だと「取れているはずの値が取れていない」「どこでエラーが出たか分からない」が起きやすくなります。

スプレッドシート取得の基本(openById)

最初にやることは、「どのスプレッドシートを操作するか」を決めることです。
最もよく使われるのは、スプレッドシートIDを指定して開く方法です。


const ss = SpreadsheetApp.openById('スプレッドシートID');

スプレッドシートIDはURLの /d/(ここ)/edit の部分に入っています。

実務では、IDをコードに直書きせず、GAS009で扱った PropertiesService に保存して参照する設計が定番です。
「IDだけ差し替えれば同じ処理を別環境に使える」「共有時にIDを晒さない」などのメリットが出ます。

シートを取得する(getSheetByName)

スプレッドシートを取得したら、次は「どのシートを操作するか」を選びます。
初心者のうちは、シート名で取得する方法が最も分かりやすく、事故も少ないです。


const sheet = ss.getSheetByName('Sheet1');

重要なポイントは、存在しないシート名を指定したとき null が返ることです。
このまま sheet.getRange(...) を呼ぶと、そこでエラーになります。
なので実務では、後述のtry-catchや存在チェックで守るのが基本です。

セル(Range)の考え方

GASでは、セルはすべて Range として扱われます。
「1セル」も実は「1行×1列の範囲」です。


const range = sheet.getRange(1, 1); // A1

Row(行)と Column(列)は1始まりです。
A1は「1行目・1列目」、B1は「1行目・2列目」になります。

また、Rangeは文字指定もできます。
この方が人間には読みやすいことも多いです。


const rangeA1 = sheet.getRange('A1');

以後の章では、基本として行列指定(getRange(row, col))を中心に説明します。

1セルの値を取得する(getValue)

1セルの値を取得する最も基本は getValue() です。


const value = sheet.getRange(1, 1).getValue();

戻り値の型は、セルの内容によって変わります。

  • 数値 → number
  • 文字列 → string
  • 日付 → Date
  • 空欄 → 空文字(または状況により空に準ずる値)

この「型が変わる」という点が、スプレッドシート操作の落とし穴になりがちです。
たとえば、数値が入っている想定で計算したら、実際は文字列で入っていて結合されてしまう、といった事故が起きます。
実務では、取得後に「空か」「型が想定どおりか」をチェックする癖をつけるのが安全です。

1セルに値を書き込む(setValue)

1セルに値を書き込む基本は setValue() です。


sheet.getRange(1, 1).setValue('完了');

これは上書きなので、「既存データを消す」可能性があります。
実務では、次のような考え方で安全性を上げます。

  • 書き込み対象のセルが正しいか(行・列がズレていないか)
  • 上書きして良い条件か(空欄のときだけ等)
  • 失敗したときに原因が追えるか(ログ)

これらを支えるのが、GAS010で扱った try-catch です。
次の章で「安全に書き込む」例を見ていきます。

try-catchで安全に「書き込む」例

スプレッドシート操作では、「シートが存在しない」「権限がない」「IDが違う」などの理由でエラーが発生します。
そのため実務では、重要な書き込み処理ほど try-catch で守ります。


function writeStatusSafe() {
  try {
    // 本来はPropertiesServiceから取得するのが定番(ここでは例として直書き)
    const ss = SpreadsheetApp.openById('スプレッドシートID');
    const sheet = ss.getSheetByName('Sheet1');

    // シート存在チェック
    if (!sheet) {
      throw new Error('Sheet1 が存在しません');
    }

    // 「A1が空欄のときだけ書き込む」など条件を入れると事故が減る
    const a1 = sheet.getRange(1, 1);
    const current = a1.getValue();

    if (current === '' || current === null) {
      a1.setValue('完了');
      Logger.log('書き込み成功:A1=完了');
    } else {
      Logger.log('書き込みスキップ:A1は既に値あり(' + current + ')');
    }
  } catch (e) {
    Logger.log('エラー発生(writeStatusSafe):' + e.message);
  }
}

ポイントは3つです。

  • 存在チェックをして、想定外の状態なら自分でエラーを投げる
  • 上書き事故を防ぐため、条件分岐で書き込み可否を決める
  • catchでは「何が起きたか」をログに残して、原因追跡できる状態にする

「書き込めたか/スキップしたか/失敗したか」がログで分かるだけでも、運用が段違いで楽になります。

try-catchで安全に「読み取る」例(追加)

次は、今回追加する取得系(読み取り)のサンプルです。
読み取りは書き込みより安全に見えますが、実務では「値が空」「型が違う」「入力ルール違反」といった問題が多く、放置すると後段処理で大きく崩れます。

ここでは、次の要件で安全に読み取ってみます。

  • Sheet1 の B2 から「数値(例:金額)」を取得する
  • 空欄や数値以外ならエラーにする
  • エラー時はログに原因を残す

function readAmountSafe() {
  try {
    const ss = SpreadsheetApp.openById('スプレッドシートID');
    const sheet = ss.getSheetByName('Sheet1');

    if (!sheet) {
      throw new Error('Sheet1 が存在しません');
    }

    const cell = sheet.getRange(2, 2); // B2
    const value = cell.getValue();

    // 1) 空欄チェック
    if (value === '' || value === null) {
      throw new Error('B2が空欄です(数値を入力してください)');
    }

    // 2) 数値チェック(スプレッドシートは型が揺れるため厳密に見る)
    // 数値ならOK。文字列なら数値変換を試みる。ダメならエラー。
    let amount;
    if (typeof value === 'number') {
      amount = value;
    } else if (typeof value === 'string') {
      const trimmed = value.trim();
      amount = Number(trimmed);
      if (!trimmed || Number.isNaN(amount)) {
        throw new Error('B2が数値ではありません:' + value);
      }
    } else {
      throw new Error('B2の型が想定外です:' + Object.prototype.toString.call(value));
    }

    // 3) 業務ルール例(マイナス禁止など)
    if (amount < 0) {
      throw new Error('B2がマイナスです:' + amount);
    }

    Logger.log('読み取り成功:B2=' + amount);
    return amount;
  } catch (e) {
    Logger.log('エラー発生(readAmountSafe):' + e.message);
    // 実務では null を返す/再スローする など方針を決める
    return null;
  }
}

この例で伝えたいのは、「読み取り時点で入力を検証する」ことです。
読み取った値が怪しいまま後続の処理に渡ると、もっと分かりにくい場所で落ちます。
“入力に近いところで止める”のが、運用しやすいGASの鉄則です。

また、ここでは説明のためIDを直書きしていますが、実務ではGAS009のとおり、スプレッドシートIDやシート名はPropertiesServiceに寄せると保守が楽になります。

PropertiesServiceを使った実務向けスプレッドシート取得

ここまでの例では説明を分かりやすくするため、 スプレッドシートIDやシート名をコードに直接書いてきました。

しかし実務では、IDやシート名をコードに直書きしない設計が基本です。
理由は次のとおりです。

  • 環境(本番・検証)ごとに差し替えやすい
  • 誤ってIDを共有・公開してしまうリスクを減らせる
  • 設定変更時にロジックを触らずに済む

これを実現するのが、GAS009で解説した PropertiesService です。

事前準備:プロパティに設定値を登録

まずは一度だけ実行する初期化関数で、設定値を登録します。


function initSpreadsheetSettings() {
  const props = PropertiesService.getScriptProperties();
  props.setProperty('SPREADSHEET_ID', 'スプレッドシートID');
  props.setProperty('SHEET_NAME', 'Sheet1');
}

この関数は初回設定専用です。 設定が終わったら削除して問題ありません。

設定値を安全に取得する関数

次に、PropertiesServiceから設定値を取得する専用関数を用意します。
ここで「未設定」を検知しておくのが重要です。


function getSpreadsheetSettings() {
  const props = PropertiesService.getScriptProperties();

  const spreadsheetId = props.getProperty('SPREADSHEET_ID');
  const sheetName = props.getProperty('SHEET_NAME');

  if (!spreadsheetId) {
    throw new Error('SPREADSHEET_ID が設定されていません');
  }
  if (!sheetName) {
    throw new Error('SHEET_NAME が設定されていません');
  }

  return { spreadsheetId, sheetName };
}

このように「設定取得」を1か所にまとめておくと、 設定ミスの検知と修正が非常に楽になります。

PropertiesService+try-catchを組み合わせた実務例

最後に、これまでの記事内容を統合した実務向けの例です。


function writeStatusUsingProperties() {
  try {
    // 設定取得
    const { spreadsheetId, sheetName } = getSpreadsheetSettings();

    // スプレッドシート・シート取得
    const ss = SpreadsheetApp.openById(spreadsheetId);
    const sheet = ss.getSheetByName(sheetName);

    if (!sheet) {
      throw new Error('シートが存在しません:' + sheetName);
    }

    const range = sheet.getRange(1, 1); // A1
    const current = range.getValue();

    if (current === '' || current === null) {
      range.setValue('完了');
      Logger.log('書き込み成功:A1=完了');
    } else {
      Logger.log('書き込みスキップ:既に値あり(' + current + ')');
    }
  } catch (e) {
    Logger.log('エラー発生(writeStatusUsingProperties):' + e.message);
  }
}

この形にしておくと、 ロジック・設定・例外処理がきれいに分離されます。

実務ではこの構成をベースに、 次回の記事で扱う「Range一括操作」や「高速化処理」へ拡張していきます。

実務で意識すべき注意点

ここまでで「1セル操作」は理解できたはずです。
ただし実務では、1セルをループで何百回も触ると遅くなります。

よくある失敗と対策をまとめます。

  • 大量セルを1つずつgetValue/setValue → 次回のRange一括操作で解決
  • 存在しないシート名で落ちる → 存在チェック+try-catch
  • 型が揺れて後段で壊れる → 読み取り時点で入力検証
  • 上書き事故 → 条件付き書き込み(空欄のみ等)

次回(GAS012)では、パフォーマンス改善にも直結するRangeの一括操作を扱います。
「遅いGAS」を「実務で耐えるGAS」に変える重要回です。

まとめ

この記事では、GASでスプレッドシートを操作するための基本として、
SpreadsheetApp → Spreadsheet → Sheet → Range の階層構造と、1セルの取得・書き込み方法を解説しました。

さらに try-catch を使った「安全な書き込み」「安全な読み取り」の例を通して、
実務で事故を減らすための考え方(存在チェック/入力検証/ログ)も整理しました。

次回は、複数セルをまとめて扱うRange一括操作へ進みます。

GAS スプレッドシート 基本操作 セル取得 書き込み try-catch 解説イメージ

0 件のコメント:

コメントを投稿