GAS×スプレッドシート実践【よく使うテクニック集】

GAS×スプレッドシート実践【よく使うテクニック集】のアイキャッチ画像
目次

GASとスプレッドシートを組み合わせれば、強力な業務ツールが作れます。

この記事では、実務でよく使うテクニックを解説します。


データ操作の基本

効率的なデータ取得

// 悪い例:1セルずつ取得(遅い)
for (let i = 1; i <= 1000; i++) {
  const value = sheet.getRange(i, 1).getValue();
}

// 良い例:一括取得(速い)
const data = sheet.getRange(1, 1, 1000, 1).getValues();
for (const row of data) {
  const value = row[0];
}

効率的なデータ書き込み

// 悪い例:1セルずつ書き込み(遅い)
for (let i = 1; i <= 1000; i++) {
  sheet.getRange(i, 1).setValue(i);
}

// 良い例:一括書き込み(速い)
const data = [];
for (let i = 1; i <= 1000; i++) {
  data.push([i]);
}
sheet.getRange(1, 1, 1000, 1).setValues(data);

最終行・列の取得

function getLastRowCol() {
  const sheet = SpreadsheetApp.getActiveSheet();

  // 最終行(データがある最後の行)
  const lastRow = sheet.getLastRow();

  // 最終列
  const lastCol = sheet.getLastColumn();

  // A列の最終行(特定列)
  const lastRowA = sheet.getRange("A:A")
    .getValues()
    .filter(row => row[0] !== "")
    .length;

  return { lastRow, lastCol, lastRowA };
}

検索・フィルタリング

値の検索

function findValue(searchValue) {
  const sheet = SpreadsheetApp.getActiveSheet();
  const data = sheet.getDataRange().getValues();

  for (let i = 0; i < data.length; i++) {
    for (let j = 0; j < data[i].length; j++) {
      if (data[i][j] === searchValue) {
        return { row: i + 1, col: j + 1 };
      }
    }
  }
  return null;
}

条件に合う行の抽出

function filterRows(columnIndex, condition) {
  const sheet = SpreadsheetApp.getActiveSheet();
  const data = sheet.getDataRange().getValues();
  const header = data[0];

  // 条件に合う行を抽出
  const filtered = data.slice(1).filter(row => {
    return condition(row[columnIndex]);
  });

  // 結果を新しいシートに出力
  const resultSheet = SpreadsheetApp.getActiveSpreadsheet()
    .insertSheet("抽出結果");
  resultSheet.appendRow(header);
  filtered.forEach(row => resultSheet.appendRow(row));

  return filtered.length;
}

// 使用例:B列が100以上の行を抽出
function extractHighValues() {
  const count = filterRows(1, value => value >= 100);
  Logger.log(`${count}件抽出しました`);
}

重複の検出

function findDuplicates(columnIndex) {
  const sheet = SpreadsheetApp.getActiveSheet();
  const data = sheet.getDataRange().getValues();

  const seen = new Map();
  const duplicates = [];

  for (let i = 1; i < data.length; i++) {
    const value = data[i][columnIndex];
    if (seen.has(value)) {
      duplicates.push({
        value: value,
        rows: [seen.get(value), i + 1]
      });
    } else {
      seen.set(value, i + 1);
    }
  }

  return duplicates;
}

データの集計

グループ別集計

function groupSum() {
  const sheet = SpreadsheetApp.getActiveSheet();
  const data = sheet.getDataRange().getValues();

  // A列でグループ化、B列を合計
  const groups = {};
  for (let i = 1; i < data.length; i++) {
    const key = data[i][0];
    const value = data[i][1];

    if (!groups[key]) {
      groups[key] = 0;
    }
    groups[key] += value;
  }

  // 結果を出力
  const resultSheet = SpreadsheetApp.getActiveSpreadsheet()
    .getSheetByName("集計") || SpreadsheetApp.getActiveSpreadsheet()
    .insertSheet("集計");

  resultSheet.clear();
  resultSheet.appendRow(["グループ", "合計"]);

  Object.entries(groups).forEach(([key, sum]) => {
    resultSheet.appendRow([key, sum]);
  });
}

ピボットテーブル的な集計

function pivotSummary() {
  const sheet = SpreadsheetApp.getActiveSheet();
  const data = sheet.getDataRange().getValues();

  // 行: A列、列: B列、値: C列の合計
  const pivot = {};
  const colKeys = new Set();

  for (let i = 1; i < data.length; i++) {
    const rowKey = data[i][0];
    const colKey = data[i][1];
    const value = data[i][2];

    if (!pivot[rowKey]) pivot[rowKey] = {};
    if (!pivot[rowKey][colKey]) pivot[rowKey][colKey] = 0;
    pivot[rowKey][colKey] += value;

    colKeys.add(colKey);
  }

  // 出力
  const colArray = Array.from(colKeys).sort();
  const output = [["", ...colArray]];

  Object.entries(pivot).forEach(([rowKey, cols]) => {
    const row = [rowKey];
    colArray.forEach(colKey => {
      row.push(cols[colKey] || 0);
    });
    output.push(row);
  });

  const resultSheet = SpreadsheetApp.getActiveSpreadsheet()
    .insertSheet("ピボット");
  resultSheet.getRange(1, 1, output.length, output[0].length)
    .setValues(output);
}

複数シートの操作

全シートのデータを統合

function mergeAllSheets() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheets = ss.getSheets();

  let mergedData = [];
  let headerAdded = false;

  sheets.forEach(sheet => {
    if (sheet.getName() === "統合") return;

    const data = sheet.getDataRange().getValues();

    if (!headerAdded) {
      mergedData.push(data[0]);
      headerAdded = true;
    }

    // ヘッダー以外を追加
    for (let i = 1; i < data.length; i++) {
      mergedData.push(data[i]);
    }
  });

  // 統合シートに出力
  let mergedSheet = ss.getSheetByName("統合");
  if (!mergedSheet) {
    mergedSheet = ss.insertSheet("統合");
  }
  mergedSheet.clear();
  mergedSheet.getRange(1, 1, mergedData.length, mergedData[0].length)
    .setValues(mergedData);
}

シートのコピーと操作

function copyAndModifySheet() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sourceSheet = ss.getSheetByName("テンプレート");

  // シートをコピー
  const newSheet = sourceSheet.copyTo(ss);
  newSheet.setName("新しいシート_" + new Date().getTime());

  // コピーしたシートを編集
  newSheet.getRange("A1").setValue("コピーしたシート");

  return newSheet;
}

外部データとの連携

CSVのインポート

function importCsvFromDrive(fileId) {
  const file = DriveApp.getFileById(fileId);
  const content = file.getBlob().getDataAsString("UTF-8");
  const data = Utilities.parseCsv(content);

  const sheet = SpreadsheetApp.getActiveSheet();
  sheet.clear();
  sheet.getRange(1, 1, data.length, data[0].length).setValues(data);
}

JSONデータの取得

function fetchJsonData() {
  const url = "https://api.example.com/data";
  const response = UrlFetchApp.fetch(url);
  const json = JSON.parse(response.getContentText());

  // スプレッドシートに出力
  const sheet = SpreadsheetApp.getActiveSheet();
  const headers = Object.keys(json[0]);
  sheet.appendRow(headers);

  json.forEach(item => {
    const row = headers.map(h => item[h]);
    sheet.appendRow(row);
  });
}

カスタムメニュー

メニューの追加

function onOpen() {
  const ui = SpreadsheetApp.getUi();
  ui.createMenu("カスタムメニュー")
    .addItem("集計を実行", "runSummary")
    .addItem("データをクリア", "clearData")
    .addSeparator()
    .addSubMenu(ui.createMenu("エクスポート")
      .addItem("CSV出力", "exportCsv")
      .addItem("PDF出力", "exportPdf"))
    .addToUi();
}

function runSummary() {
  // 集計処理
  SpreadsheetApp.getUi().alert("集計が完了しました");
}

function clearData() {
  const sheet = SpreadsheetApp.getActiveSheet();
  sheet.getRange(2, 1, sheet.getLastRow() - 1, sheet.getLastColumn()).clear();
}

確認ダイアログ

function confirmAction() {
  const ui = SpreadsheetApp.getUi();
  const response = ui.alert(
    "確認",
    "本当に実行しますか?",
    ui.ButtonSet.YES_NO
  );

  if (response === ui.Button.YES) {
    // 処理を実行
    ui.alert("実行しました");
  } else {
    ui.alert("キャンセルしました");
  }
}

実践的なツール例

在庫管理ツール

function updateStock(productId, quantity, type) {
  const sheet = SpreadsheetApp.getActiveSpreadsheet()
    .getSheetByName("在庫");
  const data = sheet.getDataRange().getValues();

  for (let i = 1; i < data.length; i++) {
    if (data[i][0] === productId) {
      const currentStock = data[i][2];
      const newStock = type === "in"
        ? currentStock + quantity
        : currentStock - quantity;

      sheet.getRange(i + 1, 3).setValue(newStock);

      // 履歴を記録
      const historySheet = SpreadsheetApp.getActiveSpreadsheet()
        .getSheetByName("履歴");
      historySheet.appendRow([
        new Date(),
        productId,
        type,
        quantity,
        newStock
      ]);

      return newStock;
    }
  }
  return null;
}

勤怠管理ツール

function recordAttendance(type) {
  const sheet = SpreadsheetApp.getActiveSpreadsheet()
    .getSheetByName("勤怠");
  const today = new Date();
  const dateStr = Utilities.formatDate(today, "JST", "yyyy/MM/dd");
  const timeStr = Utilities.formatDate(today, "JST", "HH:mm");
  const user = Session.getActiveUser().getEmail();

  sheet.appendRow([dateStr, user, type, timeStr]);
}

function clockIn() {
  recordAttendance("出勤");
  SpreadsheetApp.getUi().alert("出勤を記録しました");
}

function clockOut() {
  recordAttendance("退勤");
  SpreadsheetApp.getUi().alert("退勤を記録しました");
}

まとめ

パフォーマンスのポイント

1. データは一括で取得・書き込み
2. ループ内でgetValue/setValueを避ける
3. 配列で処理してからシートに反映

よく使うメソッド

// シート操作
sheet.getRange(row, col).getValue()
sheet.getRange(row, col, numRows, numCols).getValues()
sheet.appendRow([values])
sheet.getLastRow()

// 書式
range.setBackground(color)
range.setFontWeight("bold")

関連記事


お問い合わせ

GAS開発についてのご相談は、お気軽にお問い合わせください。

お問い合わせはこちら →


最終更新: 2025年1月

この記事をシェア

関連デモ・ツール

技術選定からご相談ください

発注範囲が決まっていなくても、現在の業務と判断したいことから整理します。

相談内容を送る

GIS・AI・業務自動化に関するご相談は お問い合わせページ からお気軽にどうぞ。