Google 試算表:刪除工作表 deleteSheet()

 


如果你的試算表已經胖到載入會喘,多半不是公式太重,是頁籤太多。

每次匯入就多一張暫存、每次月結就多一份報表副本。

與其右鍵一個個刪,不如用 deleteSheet() 規則化清理:用前綴或日期挑目標、白名單保護核心頁、先複製到備份檔,再刪原表,最後把操作寫進 Log。

本篇文章盡量說明內容,也附上自訂選單與排程範例,讓同事不會亂按、半夜也不會把整本清空。

結果是速度回來了、風險降下來,整理變成例行工作,而不是臨時救火。

希望本篇文章的內容能夠幫助到需要的您。


目錄

{tocify} $title={目錄} 


為什麼要學 deleteSheet()?

做報表或月結時,工作表越建越多:每月一張報表、每次匯入一張原始資料、每位同事複製一份版本。長期下來,檔案會膨脹、載入變慢,甚至權限管理變亂。deleteSheet() 是 Apps Script 提供的「刪除工作表」方法,用得好可以:

        自動清理過期的工作表(例如超過 90 天的暫存)。

        交接前統一刪除測試表、殘留樣板。

        例行產出新報表前,先清掉上次跑錯留下的重複頁籤。

但刪除也有風險:誤刪、刪到最後一張表、權限不足等。本文會把這些坑一次說透,並給你「先確認、再刪除、可回復」的完整做法。


基礎觀念:deleteSheet() 到底在刪什麼?


在 Apps Script 裡,deleteSheet() 是 Spreadsheet 物件的方法,用法如下:

const ss = SpreadsheetApp.getActiveSpreadsheet();
ss.deleteSheet(sheet); // 參數必須是一個有效的 Sheet 物件


幾個關鍵點:

1.    刪的是「工作表(Sheet)」,不是整個試算表(Spreadsheet)。

2.    你必須先取得要刪的那張 Sheet 物件,例如:ss.getSheetByName('Raw_2024_12')。

3.    若參數是 null/undefined、或該 Sheet 不屬於該 Spreadsheet,會丟錯。

4.    無法刪除「最後一張可見的工作表」——這是官方限制,避免檔案變成空殼。

5.    刪除動作不可撤銷(對當下動作而言),但你可以靠版本紀錄回溯;或先備份到另一份試算表再刪。


手動 vs. 程式:什麼時候用哪一種?

手動刪除(適合零星清理)

    1.    開啟試算表 → 對著要刪的工作表分頁(頁籤)按右鍵。

    2.    選 「刪除」 → 確認。

    3.    完成。

    優點:直覺、少量時最快。

    缺點:大量頁籤或規則性清理時,容易漏掉、且花時間。

用 Apps Script 刪除(適合規模化與自動化)

    批次刪除:例如同名規則、日期規則(刪除超過 90 天的歷史表)。

    專案交付前自動清場:把 TMP_ 開頭的表全部清乾淨。

    發佈新報表流程:先備份 → 再刪舊版 → 產生新版。


基礎範例 : 刪除單一工作表

function deleteSingleSheet() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheetName = 'TMP_to_delete';      // 你要刪除的表名
  const sheet = ss.getSheetByName(sheetName);

  // 防呆:確認存在
  if (!sheet) {
    throw new Error(`找不到工作表:${sheetName}`);
  }

  // 防呆:避免刪到最後一張
  if (ss.getSheets().length <= 1) {
    throw new Error('無法刪除:這是檔案中最後一張可見工作表。');
  }

  ss.deleteSheet(sheet);
}

要點:

    1.    先檢查存在性,避免 null 參數。

    2.    檢查總數,避免刪到最後一張。


批次刪除:依名稱規則清掉一批

刪除「指定前綴」的暫存表(如 TMP_

function deleteSheetsByPrefix(prefix = 'TMP_') {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheets = ss.getSheets();

  // 防呆:避免全刪
  const targets = sheets.filter(s => s.getName().startsWith(prefix));
  if (targets.length === 0) return;

  // 不要把最後一張刪光
  const available = sheets.length - targets.length;
  if (available < 1) {
    throw new Error('刪除後會變成空檔,已中止。請保留至少一張表。');
  }

  targets.forEach(s => ss.deleteSheet(s));
}


依「日期規則」刪掉過舊表(表名格式如 Raw_2025-06-15

function deleteOldSheetsByDate(days = 90, pattern = /^Raw_(\d{4}-\d{2}-\d{2})$/) {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const now = new Date();
  const sheets = ss.getSheets();

  const toDelete = sheets.filter(s => {
    const m = s.getName().match(pattern);
    if (!m) return false;
    const d = new Date(m[1]); // 由表名解析日期
    const diffDays = (now - d) / (1000 * 60 * 60 * 24);
    return diffDays > days;
  });

  if (toDelete.length === 0) return;

  if (sheets.length - toDelete.length < 1) {
    throw new Error('刪除後將無表可用,請保留至少一張。');
  }

  toDelete.forEach(s => ss.deleteSheet(s));
}


先備份、再刪除:降低風險的標準流程

做專案時,最佳實務是:「先複製到備份檔 → 再刪除原表」。好處是刪錯也有退路,不必仰賴整份檔案的版本紀錄。

function archiveThenDelete(prefix = 'TMP_', backupFileId = '你的備份試算表ID') {
  const src = SpreadsheetApp.getActiveSpreadsheet();
  const dst = SpreadsheetApp.openById(backupFileId); // 備份檔

  const targets = src.getSheets().filter(s => s.getName().startsWith(prefix));
  if (targets.length === 0) return;

  // 確保刪完仍有表存在
  if (src.getSheets().length - targets.length < 1) {
    throw new Error('刪除後檔案會變空,已中止。請保留至少一張表。');
  }

  // 逐張備份 → 刪除
  targets.forEach(sheet => {
    const temp = sheet.copyTo(dst);           // 複製到備份檔
    temp.setName(`[ARCHIVE] ${sheet.getName()} @ ${new Date().toISOString()}`);
    src.deleteSheet(sheet);                   // 再刪原表
  });
}


備份策略建議:

    1.    建一份專用「Archive」試算表,權限只給管理者。

    2.    備份表名加上時間戳,避免重名。

    3.    定期清理備份檔(例如保留近 180 天)。


常見錯誤訊息與雷點

1.    Exception: The sheet is the last visible sheet

       因為試算表不能沒有任何表。

       解法:先 insertSheet('KEEP') 新增一張占位表,再刪。

2.    Exception: You do not have permission to call deleteSheet / 權限不足

       你的帳號沒有編輯權限或該表受保護。

        解法:

        確認檔案權限、移除保護、改用擁有權限的帳號或部署 Web App 以擁有者身份執行(需謹慎)。

3.    Cannot call Spreadsheet.deleteSheet with null.

       傳入的 sheet 為 null。

       解法:先 getSheetByName() 檢查是否存在,不存在就中止並提示。

4.    誤刪表單回應

       刪掉「表單回應 1」會把歷史回應資料一起拿掉。

       解法:先 copyTo() 備份到另一份檔案或轉存到資料庫,再刪。

5.    批次刪到關鍵頁籤

       用前綴/規則選取時,可能把 Template 或 Config 誤刪。

       解法:加入白名單保護、乾跑模式、手動複核名單。


問題集

Q1:刪除後可以復原嗎?

單次動作無法「撤銷」,但你可以到「檔案 → 版本紀錄」回溯到某個時間點;或若有用上文備份招,去備份檔把對應表複製回來。

Q2:為什麼我明明是編輯者,卻刪不了某張表?

該表可能被設「保護工作表」,且沒把你加進允許名單。聯絡擁有者調整保護或請擁有者執行刪除腳本。

Q3:可不可以刪除多個指定名稱?

可以,建立一個名單陣列迭代處理,再套上「最後一張防呆」。

function deleteByNames(names = ['A','B','C']) {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheets = ss.getSheets();
  const targets = names
    .map(n => ss.getSheetByName(n))
    .filter(Boolean);

  if (targets.length === 0) return;
  if (sheets.length - targets.length < 1) {
    throw new Error('刪除後將無表可用。');
  }
  targets.forEach(s => ss.deleteSheet(s));
}

Q4:怎麼避免別人誤觸批次刪除?

把批次刪除功能放進「管理員選單」,或在 menuDeleteTmp() 前加使用者信箱判斷,只允許特定帳號執行。

function onlyAdminCanRun_() {
  const allowed = ['you@company.com'];
  const me = Session.getActiveUser().getEmail();
  if (!allowed.includes(me)) {
    throw new Error('你無權執行此操作,請聯絡管理員。');
  }
}


延伸閱讀推薦:

張貼留言 (0)
較新的 較舊